Gradle plugin for default properties - groovy

I am trying (and failing :) ) to create a gradle plugin that has a default set of versions for dependencies and can be overridden in the gradle.build file that is calling my plugin. Ideally something like the sudo-code below
MyDefaultPropertiesPlugin.groovy
project.versions.springBoot="1.0.0-RELEASE"
MyPlugin.groovy
project.apply plugin: MyDefaultPropertiesPlugin
compile("org.springframework.boot:spring-boot-starter-web:${project.versions.springBoot}")
build.gradle
versions.springBoot = "1.1.0-RELEASE"
project.apply plugin "my.plugin"
I attempted to do using extensions but ran into isssue's via the ordering when overriding. (versions doesnt exist)
I would greatly appreciate any advise on this, maven would be easy, but my gradle knowledge is still evolving :)
Thanks in advance for any insight!

Plugins have to defer accessing the build model until after build scripts have been evaluated. Easiest solution is to use project.afterEvaluate {}, but there are others. For more information, see answers to similar questions here or on http://forums.gradle.org.

Came up with a pretty workable if not perfect solution, I will update if i think of anything better, my gradle is at a learning level, so please commend if this can be improved.
This allows me to define a set of versions and clients to overwrite those versions with a simple property
MyDefaultVersionsPlugin.groovy
class MyDefaultVersionsPlugin implements Plugin<Project>{
project.extensions.create('versions', MyVersions, project)
}
class MyVersions{
String spring
String slf4j
public MyVersions (Project project){
spring = setVersion(project,'springVersion', 'x.x.x.x')
slf4j = setVersion(project,'slf4jVersion', 'x.x.x.x')
}
private static String setVersion(Project project, String name, String version){
if(project.hasProperties(name)){
return project.getProperties().get(name)
}
else {
return version
}
}
}
MyPlugin.groovy
project.apply plugin: MyDefaultVersionsPlugin
compile("org.springframework.boot:spring-boot-starter-web:${project.versions.spring}")
build.gradle
buildscript { ext { springVersion = 'x.x.x.x'} }

Related

Kotlin / Gradle DSL integration to manage dependency version variables

Kotlin / Gradle DSL integration to manage dependency version variables
My question is about the best way to manage dependency version variables in IntelliJ Idea / Android Studio using Gradle
Kotlin DSL
The secondary purpose is to have the IDE perform version upgrades upon clicking the suggestion to change to newer
version automatically instead of manually editing the versioning file entry.
the simple way
definition
build.gradle.kts
plugins {
application
kotlin("jvm") version "1.7.10"
}
dependencies {
implementation("io.ktor:ktor-server-core-jvm:2.1.1")
}
Comments
This is working but "clumsy" and does not comply to single source of truth (SSOT)
I have seen several ways that attempt having a SSOT for the dependency versions
by Project
Definition
gradle.properties
ktor_version = 2.1.0
kotlin_version = 1.7.10
build.gradle.kts
val ktor_version: String by project // NOTE the complaint Property name 'ktor_version' should not contain underscores
val kotlin_version: String by project
plugins {
application
kotlin("jvm") version "1.7.10" // NOTE you cannot replace this with the variable!
// 'val kotlin_version: String' can't be called in this context by implicit receiver. Use the explicit one if necessary
}
dependencies {
implementation("io.ktor:ktor-server-core-jvm:$ktor_version")
}
Comments
This does not update the suggested version numbers via "Project Structure/Suggestions" in AS/IJ
my inline NOTES indicate several issues with this method!
by buildSrc java Module
Definition
object Ktor {
private const val ktorVersion = "2.0.0"
const val core = "io.ktor:ktor-client-core:${ktorVersion}"
const val android = "io.ktor:ktor-client-android:${ktorVersion}"
}
implementation in build.gradle.kts
implementation(Ktor.android)
Comments
This does not update the suggested version numbers via "Project Structure/Suggestions" in AS/IJ, is seemed to
be totally de-coupled, and it is a nightmare to manually find and update the versions manually to the latest!
However: doing it by buildSrc java Module makes it much easier to re-use in other projects
by Gradle Version Catalogs
Definition
libs.versions.toml // in the gradle directory next to wrapper
[versions]
plugin-kotlin = "1.7.10"
ktor = "2.1.0"
[libraries]
plugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "plugin-kotlin" }
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
[bundles]
plugins = ["plugin-android", "plugin-kotlin", "plugin-kotlin-serialization", "plugin-sqldelight"]
implementation in build.gradle.kts(project)
buildscript {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
dependencies {
classpath(libs.bundles.plugins)
}
}
implementation in build.gradle.kts(shared)
sourceSets {
val commonMain by getting {
dependencies {
implementation(libs.ktor.client.core)
}
}
}
Comments
This is by far the favorite of mine, the reason is clear, it allows SSOT, and it allows grouping/bundling to make
"sets" that is more understandable later on
However!
This does not update the suggested version numbers via "Project Structure/Suggestions" in AS/IJ
it is a nightmare to manually find and update the versions manually to the latest!
Main question
Is there a better way of managing dependency versions?
Is there a way that works inside the IDE AS/IJ suggestions to update the versions correctly at the definition
location?

Groovy how can I build a custom library and use it in a project as dependency

I have a set of code procedures I use in a lot of places and I'm trying to basically move it to a library.
So I created my library with some unit test and everything was looking promising and at least working localy..
When I went to my project and deleted the files locally and then try to import them from my library as a dependency the code does not work.
I always get this kind of error
Class does not define or inherit an implementation of the resolved method abstract getProperty(Ljava/lang/String;)Ljava/lang/Object; of interface groovy.lang.GroovyObject.
I'm definitely not an expert on groovy but basically I use it in my Jenkins and Gradle for pipelines and some basic packaging or environment deployments.
I can show my class:
class ConsoleRow implements Comparable {
...
final Integer priority
final String rowStatus
final String message
final String rowReportClass
ConsoleRow(Integer priority, String status, String msg, String rowC) {
this.priority = priority
this.rowStatus = status
this.message = msg
this.rowReportClass = rowC
}
#Override
int compareTo(Object o) {
return this.priority <=> ((ConsoleRow) o).priority
}
The line that gives me the error is this actual compareTo when trying to do the "this.priority"
Caused by: java.lang.AbstractMethodError: Receiver class com.abc.insight.jenkins.ConsoleRow does not define or inherit an implementation of the resolved method abstract getProperty(Ljava/lang/String;)Ljava/lang/Object; of interface groovy.lang.GroovyObject.
at com.abc.insight.jenkins.ConsoleRow.compareTo(ConsoleRow.groovy:24)
at com.abc.insight.jenkins.ConsoleOutputHtmlBuilder.processOutput(ConsoleOutputHtmlBuilder.groovy:115)
at com.abc.insight.jenkins.ConsoleOutputHtmlBuilder.processOutput(ConsoleOutputHtmlBuilder.groovy)
at com.abc.insight.jenkins.ConsoleOutputHtmlBuilder.buildReport(ConsoleOutputHtmlBuilder.groovy:20)
at com.abc.insight.jenkins.ConsoleOutputHtmlBuilder$buildReport.call(Unknown Source)
at build_e548mc0tqjmi822clitlsycdk.runReport(C:\dev\repo\insight\insight-health-check\data-foundation\smoke-test\build.gradle:77)
The calling function is just trying to sort a list of those objects
List<ConsoleRow> outputRows = []
...
return outputRows.sort()
The part that gets me really confused is that if instead of importing the library as a dependency I just do this directly in this repo and put my sources in my buildSrc\src\main\groovy\com\abc\insight the code works fine...
So I really think it might be how I package and publish my library that might be wrong.
I'm really sure this is some basic error on my part because I never did a groovy library before but somehow I can't make it work.
It might be that my publication is just wrong, on my library side I'm using this plugins to do the publishing.
plugins {
id 'groovy'
id 'java-library'
id 'base'
}
publishing {
publications {
maven(MavenPublication) {
from components.java
}
}
}
I tried to change components.groovy but somehow it does not work.
Any ideas or tips, I think my question probably is showing some really lack of know-how on groovy but looking at the documentation and examples I could not figure it out.
Doing some debug in my IDE the compareTo that generates the exception looks like this.
public int compareTo(Object o) {
CallSite[] var2 = $getCallSiteArray();
return ScriptBytecodeAdapter.compareTo(this.priority, var2[0].callGroovyObjectGetProperty((ConsoleRow)ScriptBytecodeAdapter.castToType(o, ConsoleRow.class)));
}
I tried following this guide and code structure when doing moving the code to a library
https://docs.gradle.org/current/samples/sample_building_groovy_libraries.html
Thanks for any feedback
p.s: My code might look weird, I tried first to have everything with the def blablabla but I was having some issues with typecasting but I don't think this would be the reason for the problem I'm facing.
Anyway I got a look at the generated code in my IDE and I see a lot of get methods just no idea where they expected this getProperty from
Ok this was definitely a user error.
I am using distribution version of gradle 6.5.1
When I did the gradle init to bootstrap my project I was provided with the dependency of gradle groovy-all version 2.5.11
implementation group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.5.11'
I thought that was a mistake and just updated to the latest version.
implementation group: 'org.codehaus.groovy', name: 'groovy-all', version: '3.0.9'
Now the problem is that the project in which I'm using the library is also running with gradle 6.5.1 so probably this version missmatch between compiple and usage was causing the problem.
By reverting to the correct version suggested by gradle the problem is gone.

Gradle, overload extension setter

Given an extension registered in gradle as foo:
class Foo {
Project proj
void setProject( Project project) {
this.proj = project
}
void setProject( String project) {
// do stuff
}
}
How do I get:
foo {
project = ':random-project'
}
to call the string setter and not fail in setProperty of the decorated extension object due to GroovyCastException?
The reason for this question arose from this issue: https://github.com/Centril/gradle-plugin-robospock/issues/5
Since I don't see any better answer yet, I am trying to suggest a possible alternative.
If you can keep type of proj as a String in Foo and where you actually use the instance of Foo class, lookup the project using the findProject method on the project object available to your plugin.
class FooPlugin implements Plugin<Project> {
// ...
void apply(Project project) {
// ...
project.findProject(fooInstance.proj)
}
}
You may find more on findProject or project methods to locate a project by path at API Documentation
There might be a way to access current Project instance in your Foo class then you may use the overloaded setter.
This works in Gradle versions 2.0 and later which is likely due to the move from Groovy 1.x to 2.x. I'd suggest using a later version of Gradle if that is possible.
Luke Daley from Gradleware informed me that this is a limitation of the Groovy language: https://issues.apache.org/jira/browse/GROOVY-2500

How can I specify a Groovy CompilerConfig using Gradle?

I have a Groovy project, where I would like to enable this CompilerConfig:
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
ast(groovy.transform.TypeChecked)
}
How can I enable this using Gradle?
Beginning from Gradle 2.1 it is possible, see the corresponding release notes.
This is especially useful for working with Groovy on Android, see this presentation. E.g. you could add the #CompileStatic to each class with the following code:
File build.gradle
compileGroovy {
groovyOptions.configurationScript = file("gradle/config.groovy")
}
File gradle/config.groovy
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
}
For more options, see the GroovyCompileOptions and Groovy Customizer Builder.
Gradle's GroovyCompile task doesn't currently support passing a CompilerConfiguration instance or --configscript option. See http://forums.gradle.org/gradle/topics/ability_to_specify_a_compilerconfiguration_instance_for_groovycompile_task for a related discussion.

How to refer to the values to be declared in build.gradle

I'm totally new to this gradle, teamcity and groovy.
I'm tryign to write a plugin,which will get the value from svninfo. If the developer wants to override the value(in build.gradle) they can override something like this.
globalVariables{
virtualRepo = "virtualRepo"
baseName = "baseName"
version = "version"
group = "group"
}
Here i provide the extension called globalvariable.
Now, The jars to be produced shd hav the name according to the values from the build.gradle..
How to get the value from build.gradle in the plugin inorder name the jar???
Not sure I understand the question. It's the plugin that installs the extension object, and it's the plugin that needs to do something with it.
Note that the plugin has to defer reading information from the extension object because the latter might only get populated after the plugin has run. (A plugin runs when apply plugin: is called in a build script. globalVariables {} might come after that.) There are several techniques for deferring configuration. In your particular case, if I wanted to use the information provided by the extension object to configure a Jar task, I might use jar.doFirst { ... } or gradle.projectsEvaluated { jar. ... }.
Before you go about writing plugins, make sure to study the Writing Custom Plugins chapter in the Gradle user guide. A search on Stack Overflow or on http://forums.gradle.org should turn up more information on techniques for deferring configuration. Another valuable source of information is the Gradle codebase (e.g. the plugins in the code-quality subproject).

Resources