getVersion() in custom Gradle plugin is always unspecified - gradle

Related to
How to Get $project.version in Custom Gradle Plugin?
Executive summary: getVersion() inside of custom gradle plugin returns "unspecified"
I have created a custom gradle plugin that applies some business logic to our Android Studio / Gradle builds. This plugin is run every time we do a CI build.
I want the plugin to be able to print out its version, which is an entirely different version number from that of the Android application being built, during builds. (useful debugging information during CI builds)
The build.gradle for the plugin (that gets deployed to a maven repo as a jar):
buildscript {
repositories {
mavenCentral()
}
}
apply plugin: 'groovy'
apply plugin: 'maven'
group = 'com.example.foo.gradle'
version = "0.0.12"
sourceCompatibility = JavaVersion.VERSION_1_6
targetCompatibility = JavaVersion.VERSION_1_6
dependencies {
repositories {
mavenCentral()
}
compile gradleApi()
compile localGroovy()
}
configurations {
includeInJar
}
dependencies {
//testCompile 'junit:junit:4.11'
}
jar {
}
uploadArchives {
repositories.mavenDeployer {
def deployPath = file(getProperty('aar.deployPath'))
repository(url: "file://${deployPath.absolutePath}")
pom.project {
groupId project.group
artifactId 'foo-gradle-jenkins'
version project.version
}
}
}
... and the plugin is applied to an Android app like this (sensitive parts omitted):
buildscript {
repositories {
mavenCentral()
maven { url "../../../plugin_builds" }
}
dependencies {
classpath 'com.example.foo.gradle:foo-gradle-jenkins:0.0.+'
}
}
apply plugin: 'com.android.application'
apply plugin: 'foo'
android {
compileSdkVersion 20
buildToolsVersion "20.0.0"
defaultConfig {
applicationId "com.example.android.examplegradleapplication3"
minSdkVersion 14
targetSdkVersion 20
versionCode 1
versionName "1.0"
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
In the plugin I attempt to print its version like this:
#Override
void apply(Project project) {
project.configure(project) {
if (it.hasProperty("android")) {
if (isJenkinsBuild()) {
log("Plugin version: " + getVersion())
// ...
}
// ...
}
}
}
.. but whenever I perform gradle build of the Android app it thinks getVersion() is unspecified.
What should I be doing instead to track the plugin version at the time of another gradle build using it as a plugin?

AppExtension android = (AppExtension) project.extensions.findByName("android")
String versionName = android.defaultConfig.versionName
String versionCode = android.defaultConfig.versionCode

project.configure(project) { println getVersion() } is the same as println project.version. If this prints unspecified, the build script didn't set (project.)version.
As of Gradle 2.2, there isn't a built-in way for a plugin to declare or query its own version, but you could implement this yourself (for your own plugins).

Related

BootJar + MavenJar. Artifact wasn't produced by this build

I have a sample project with the following hierearhy:
Sample (root)
-- model (simple jar)
-- api (springboot jar)
I want to publish both generated jars: plain jar & bootJar to my localRepository.
gradlew clean build -xTest publishToMavenLocal
However, the following error occures:
* What went wrong:
Execution failed for task ':api:publishMavenJavaPublicationToMavenLocal'.
> Failed to publish publication 'mavenJava' to repository 'mavenLocal'
> Artifact api.jar wasn't produced by this build.
The root build.gradle is a follows:
plugins {
id 'java'
id "org.springframework.boot" version "2.2.5.RELEASE" apply false
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
}
group 'sample'
version '1.0-SNAPSHOT'
apply plugin: 'java'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
ext {
artifactVersion = version
springBootVersion = "2.2.5.RELEASE"
}
allprojects {
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'maven'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
repositories {
mavenCentral()
jcenter()
}
}
subprojects {
apply plugin: "io.spring.dependency-management"
apply plugin: "maven-publish"
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
dependencyManagement {
imports {
mavenBom "org.springframework.boot:spring-boot-dependencies:${springBootVersion}"
}
}
dependencies {
implementation "org.springframework.boot:spring-boot-dependencies:${springBootVersion}"
}
publishing {
publications {
mavenJava(MavenPublication) {
groupId project.group
artifactId project.name
version project.version
from components.java
}
}
}
}
api build.gradle
apply plugin: 'org.springframework.boot'
dependencies {
compile project(":model")
implementation "org.springframework.boot:spring-boot-starter-web"
}
bootJar {
}
Adding bootJava task to api build.gradle allowes to publish the bootJar directly from api module, but the root publish task remains broken.
publishing {
publications {
bootJava(MavenPublication) {
artifact bootJar
}
}
}
I've tried almost every solution from docs & google, but none seem to work.
Can anyone explain, what is misconfigured?
Gradle version: 6.3
As stated by gradle documentation here:
Starting from Gradle 6.2, Gradle performs a sanity check before uploading, to make sure you don’t upload stale files (files produced by another build). This introduces a problem with Spring Boot applications which are uploaded using the components.java component
More explanation is available in the link above.
They propose the following workaround that I personally tried and worked for me :
configure the outgoing configurations
configurations {
[apiElements, runtimeElements].each {
it.outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(jar) }
it.outgoing.artifact(bootJar)
}
}
here after the configuration from my build.gradle:
....
apply plugin: 'maven-publish'
...
configurations {
[apiElements, runtimeElements].each {
it.outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(jar) }
it.outgoing.artifact(bootJar)
}
....
}
publishing {
publications {
myPublication(MavenPublication) {
groupId groupId
artifactId artifactId
version version
from components.java
versionMapping {
usage('java-api') {
fromResolutionOf('runtimeClasspath')
}
usage('java-runtime') {
fromResolutionResult()
}
}
}
}
repositories {
maven {
url azureRepoUrl
name azureRepoName
credentials {
username azureRepoUserName
password azureRepoAccessToken
}
}
}
}
Excerpt from
Starting from Gradle 6.2, the main jar task is disabled by the Spring Boot application, and the component expects it to be present. Because the bootJar task uses the same file as the main jar task by default, previous releases of Gradle would either:
publish a stale bootJar artifact
or fail if the bootJar task hasn’t been called previously
To simple workaround would be configuring the outgoing configurations. For multi-module Gradle project, place the below configuration in the service module(spring boot module).
dependencies {
.....
}
configurations {
[apiElements, runtimeElements].each {
it.outgoing.artifacts.removeIf {
it.buildDependencies.getDependencies(null).contains(jar)
}
it.outgoing.artifact(bootJar)
}
}
Note: There is no need for changing anything with artifactory task if it was configured correctly. This working solution has been tested with Gradle 6.4.1.
Don't try the alternate suggestion that they provided, because classifier attribute is deprecated in recent versions, also altering the bootJar task with custom configuration would result in improper uber jar construction, and if you extract the generated jar distributive, you could find the missing BOOT-INF directory and necessary META-INF/MANIFEST.MF values.
jar {
enabled = true
}
bootJar {
classifier = 'application'
}
Update:
From Spring Boot 2.5.0, jar task generates an additional jar archive which ends with -plain.jar. It may break someone's build if they have used some patterns like *.jar to copy the build archive, hence, to restrict the additional jar creation, the following jar task configuration code snippet should be used.
jar {
enabled = false
}
I could get this worked by just adding artifact bootJar in the publishing task as shown below and with out adding any configurations as suggested in the gradle documentation. I believe this could be working same as their first workaround in the documentation. Tested with gradle 6.5.1
publishing {
publications {
mavenJava(MavenPublication) {
artifact bootJar
artifact sourceJar {
classifier "sources"
}
}
}
}
project.tasks.publish.dependsOn bootJar
According to the 'Gradle' documentation under,
https://docs.gradle.org/current/userguide/upgrading_version_6.html#publishing_spring_boot_applications
Just add the following to the build.gradle file
jar {
enabled = true
}
bootJar {
classifier = 'application'
}
If you are using gradle kotlin dsl add the equivalent in your build.gradle. It worked for me
configurations {
val elements = listOf(apiElements, runtimeElements)
elements.forEach { element ->
element.get().outgoing.artifacts.removeIf { it -> it.buildDependencies.getDependencies(null).contains(tasks.jar.get())}
element.get().outgoing.artifact(tasks.bootJar.get())
}
}
For Spring Boot 2.5.0+, this configurations works for publishing the embedded jar, its sources and javadoc:
plugins {
id 'maven-publish'
id 'java-library'
}
jar {
enabled = false
}
java {
withSourcesJar()
withJavadocJar()
}
publishing {
publications {
publication(MavenPublication) {
artifact bootJar
from components.java
}
}
}

Gradle (Kotlin DSL): "Unresolved reference: proguard"

Im trying to get Proguard to work but Im still new to Gradle.
My build gradle.kts haves an error (Unresolved reference: proguard), I cant create a proguard Task:
plugins {
id("com.github.johnrengelman.shadow") version "5.2.0"
java
kotlin("jvm") version "1.3.61"
}
group = "*...*"
version = "*...*"
repositories {
mavenCentral()
jcenter()
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
//*...*
implementation("net.sf.proguard","proguard-gradle","6.2.2") //is this correct?
}
configure<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_1_8
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
jar{
manifest {
attributes["Main-Class"] = "*...*"
}
}
shadowJar{
archiveBaseName.set("*...*")
archiveClassifier.set("")
archiveVersion.set("")
}
register<proguard.gradle.ProGuardTask>("myProguardTask") { //Unresolved reference: proguard
}
}
This is not an Android Project
Because Stackoverflow wants me to write more than just code: Im planing to somehow link the proguard output to the shadowjar task. If you know how to do it Im also interested to that (and I could not try it myself because of this problem).
You declared a dependency of proguard in project rather than for Gradle itself.
Move the dependency to the buildscript block:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'net.sf.proguard:proguard-gradle:6.2.2'
}
}
Then you should be able to create your task.
Alternatively, you can declare the repository in settings.gradle.kts:
pluginManagement {
repositories {
jcenter()
}
}
which will trim down the buildscript block in build.gradle.kts:
buildscript {
dependencies {
classpath("net.sf.proguard:proguard-gradle:6.2.2")
}
}

How to rename file after project is builded in gradle 5 kotlin DSL

Could you please help me to find a proper way to rename built artifact with Gradle 5 Kotlin DSL
I created a Gradle 5.5.1 Spring Boot 2 project based on Kotlin DSL.
After executing gradle build the built artifact is inside $buildDir/libs folder.
How can I rename it? Let's say I want to give a simple name - app.jar
plugins {
id("java")
id("idea")
id("org.springframework.boot") version "2.1.5.RELEASE"
id("io.spring.dependency-management") version "1.0.8.RELEASE"
}
group = "com.hbv"
version = "1.0.0-SNAPSHOT"
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.5.RELEASE")
}
}
the<DependencyManagementExtension>().apply {
imports {
mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
}
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation(platform("org.springframework.cloud:spring-cloud-dependencies:Greenwich.RELEASE"))
implementation("org.springframework.cloud:spring-cloud-starter-config")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-security")
testImplementation("com.h2database", "h2")
testImplementation("org.springframework.boot", "spring-boot-starter-test")
testImplementation("org.springframework.security", "spring-security-test")
}```
Configure the bootJar task which is generating the jar and is a gradle jar task and set its archiveFileName property:
tasks {
bootJar {
archiveFileName.set("app.jar")
}
}
define archiveBaseName in jar task
tasks.withType<Jar> {
archiveBaseName.set("app")
manifest {
attributes["Main-Class"] = application.mainClass
attributes["Implementation-Version"] = archiveVersion
attributes["Implementation-Title"] = "Test for App"
}
}

How can I convert a groovy task in gradle into Gradle Kotlin DSL to generate a pom.xml?

What is the build.gradle.kts version of the the following Gradle script?
apply plugin: 'maven'
apply plugin: 'java'
sourceCompatibility = 7
targetCompatibility = 7
dependencies {
compile 'com.google.guava:guava:13.0.1'
compile 'joda-time:joda-time:2.1'
testCompile 'junit:junit:4.11'
testCompile 'org.mockito:mockito-core:1.9.5'
}
task writeNewPom << {
pom {
project {
groupId 'org.example'
artifactId 'test'
version '1.0.0'
inceptionYear '2008'
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution 'repo'
}
}
}
}.writeTo("$buildDir/newpom.xml")
}
References
1- Gradle sample was here.
I believe this is the same as a build.gradle.kts file:
plugins {
java
maven
}
java {
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
repositories {
jcenter()
}
dependencies {
compile("com.google.guava:guava:13.0.1")
compile("joda-time:joda-time:2.1")
testCompile("junit:junit:4.11")
testCompile("org.mockito:mockito-core:1.9.5")
}
tasks {
"writeNewPom" {
doLast {
project.the<MavenPluginConvention>().pom {
project {
groupId = "org.example"
artifactId = "test"
version = "1.0.0"
withGroovyBuilder {
"inceptionYear"("2008")
"licenses" {
"license" {
"name"("The Apache Software License, Version 2.0")
"url"("http://www.apache.org/licenses/LICENSE-2.0.txt")
"distribution"("repo")
}
}
}
}
}.writeTo("$buildDir/newPom.xml")
}
}
}
You have to use the withGroovyBuilder method to add the untyped properties to the model

gradle conflicting transitive dependency not being included

I have a dependency, my-project that uses two dependencies that use different versions of commons-lang3 but when I build my war artifact, commons-lang3 is not included in the artifact. What could be wrong?
My build.gradle looks like:
apply plugin: 'io.spring.dependency-management'
apply plugin: 'java'
apply plugin: 'maven-publish'
apply plugin: 'war'
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'io.spring.gradle:dependency-management-plugin:0.3.0.RELEASE'
}
}
compileJava {
sourceCompatibility = 1.7
targetCompatibility = 1.7
}
configurations.all {
exclude group: 'commons-logging'
}
repositories {
jcenter()
maven {
credentials {
username = "${artifactory_user}"
password = "${artifactory_password}"
}
url "myrepo.com"
}
}
dependencyManagement {
imports {
mavenBom 'io.spring.platform:platform-bom:1.1.2.RELEASE'
}
}
dependencies {
compile "my.project:my-project:1.0.0-SNAPSHOT"
// Spring Framework
compile 'org.springframework:spring-context'
compile 'org.springframework:spring-web'
compile 'org.springframework:spring-webmvc'
compile 'org.springframework.security:spring-security-config'
compile 'org.springframework.security:spring-security-web'
// Jackson
compile "com.fasterxml.jackson.core:jackson-annotations"
compile "com.fasterxml.jackson.core:jackson-core"
compile "com.fasterxml.jackson.core:jackson-databind"
// Logging
compile 'ch.qos.logback:logback-classic'
compile 'org.slf4j:slf4j-api'
runtime 'org.slf4j:jcl-over-slf4j'
runtime 'org.logback-extensions:logback-ext-loggly:0.1.2'
// Test
testCompile 'junit:junit'
testCompile 'org.mockito:mockito-core'
testCompile 'org.springframework:spring-test'
providedCompile 'javax.servlet:javax.servlet-api'
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.web
}
}
repositories {
maven {
credentials {
username = "${artifactory_user}"
password = "${artifactory_password}"
}
if(project.version.endsWith('-SNAPSHOT')) {
url "myrepo.com/libs-snapshot-local"
} else {
url "myrepo.com/libs-release-local"
}
}
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.4'
}
EDIT Dependency diagram of my.project:my-project
my-project is a library project that my co-worker wrote that is dependent on two other library projects that contain commons-lang3. An example diagram would be
my.project:my-project:1.0.0-SNAPSHOT
+---my.project:my-dependency-1:1.0.0
| +---org.apache.commons:commons-lang3:3.4
+---my.project:my-dependency-2:1.0.0
+---org.apache.commons:commons-lang3:3.3.2
I updated the spring gradle dependency-management-plugin to 0.5.2.RELEASE and that fixed my problem.

Resources