How to get the library module's version from inside the module's code at runtime - android-library

Having a Android library module, its version is defined in the build.gradle
group = 'com.sample.data'
version = 1.0.1
project.ext.artifactId = 'data_module'
apply plugin: 'com.android.library'
Inside its code when do log or reporting the crash it needs to include itself's version (the 1.0.1).
using
val pInfo = context.getPackageManager()
.getPackageInfo(dataConfiguration.context.getPackageName(), 0)
val version = pInfo.versionName
only gets the hosting app's package info, not the library module's
How to get the library module's version from inside the module's code at runtime?
some post suggest to use the BuildConfig.VERSION_NAME, but in the library module's code it cannt not be resolved (the list does not have the library itself)

After adding same extra stuff in build.gradle's
defaultConfig {
}
in the code the BuildConfig.VERSION_NAME is resolved.
It can get the version from BuildConfig.VERSION_NAME.

Related

Gradle Idea plugin - issues with specifing test sources

I'm trying to create a custom source set and mark its contents in Intellij Idea as a Test Sources Root. I tried to use idea plugin and do it according to the gradle official website but it is not clear for me how it works.
First of all the documentation specifies the following configuration setup
idea {
module {
testSources.from(sourceSets["intTest"].java.srcDirs)
}
}
When I try to use it i receive Unresolved reference: testSources. Where is it coming from?
Then I tried to use:
idea {
module {
testSourceDirs = intTest.java.srcDirs
}
}
it works fine as long as I use only Java. After applying Kotlin plugin however, both kotlin and java + resources folder are again treated as Sources Root not Test Sources. To fix that I had to change from:
testSourceDirs = intTest.java.srcDirs
to:
testSourceDirs = intTest.kotlin.srcDirs
and now all folders are Test Source Root again. Since kotlin.srcDirs also includes java.srcDirs it looks like you have to specify all, otherwise it is ignored...
Now the real issue came when I used gradle-avro-plugin. Applying it made my folders marked as Sources Root again. I believe it is because it adds another avro directory, but just to main source set.
Does anyone know how to make it marked as Test Sources having both kotlin and avro plugin applied? Am I doing something wrong here? Beacause this beheviour seems to be buggy in the first place.
Tested with:
IntelliJ IDEA 2022.3.1 (Ultimate Edition)
Gradle 6.8.3 and 7.4.2
Plugin id("com.github.davidmc24.gradle.plugin.avro") version "1.5.0"
Plugin kotlin("jvm") version "1.7.0"

Gradle bundle import to module

I am trying to import base to a project, but I get an error.
settings.gradle
enableFeaturePreview('VERSION_CATALOGS')
dependencyResolutionManagement {
versionCatalogs {
libs {
// https://mvnrepository.com/artifact/org.springframework/spring-core
version('spring', '5.3.14')
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter
version('spring-boot', '2.6.2')
alias('spring-core').to('org.springframework', 'spring-core').versionRef('spring')
alias('spring-context').to('org.springframework', 'spring-context').versionRef('spring')
alias('spring-boot').to('org.springframework.boot', 'spring-boot-starter').versionRef('spring-boot')
bundle('base', ['spring-core', 'spring-context'])
}
}
}
module's build.gradle
dependencies {
implementation(libs.base)
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}
refreshing gradle will produce the following error
Could not get unknown property 'base' for extension 'libs' of type org.gradle.accessors.dm.LibrariesForLibs.
How to import libs.base correctly?
The correct way of referencing a bundle from a version catalog is
libs.bundles.base
Similarly for plugins use:
libs.plugins.yourplugin
It is also possible to reference versions, but this works slightly different. For example:
implementation group: "org.springframework.boot", name: "spring-boot-starter-web-services", version: libs.versions.spring.boot.get()
This assumes a version definition in your catalog which looks like:
version('spring-boot', '2.6.7')
Note that bundles, versions and plugins are all spelled as plural.
Also note that as of Gradle 7 version catalogs are no longer a feature preview. They are available by default. Also, the notation for libraries has changed slightly. You have to use library instead of alias.
See Gradle's support site for more information.

Gradle7 Version Catalog: How to use it with buildSrc?

I am very excited about the incubating Gradle's version catalogs and have been experimenting with it. I’ve found that the information in my gradle/libs.versions.toml is accessible in the build.gradle.kts scripts for my app and utility-lib projects.
However, I am unable to use the content of the toml file for buildSrc/build.gradle.kts or the convention files.
The only way that I could build was to hard-code the dependencies into those files, as I did before the version catalog feature.
In the buildSrc folder, I created a settings.gradle.kts file and inserted the dependencyResolutionManagement code for versionCatalogs, which is pointing to the same file as for my app and utility-lib projects.
Based on the Gradle7 docs, it seems that sharing a version catalog with buildSrc and modules is possible… I’d appreciate a nudge into getting it to work with buildSrc, if possible.
Here is a simple sample project, which I created via gradle init: my-version-catalog
Thank you for your time and help,
Mike
With Gradle 7.3.3, it is possible. Note version catalogs are GA since Gradle 7.4
The code snippet assumes Gradle is at least 7.4, but if you need them prior that version, insert enableFeaturePreview("VERSION_CATALOGS") at the beginning of each settings.gradle.kts.
Using buildSrc
buildSrc/settings.gradle.kts
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
buildSrc/build.gradle.kts
dependencies {
implementation(libs.gradleplugin.intellij) // <- the lib reference
}
You can even use the version catalog for plugins
gradle/libs.versions.toml
...
[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
jetbrains-changelog = { id = "org.jetbrains.changelog", version.ref = "changelog-plugin" }
jetbrains-intellij = { id = "org.jetbrains.intellij", version.ref = "intellij-plugin" }
hierynomus-license = { id = "com.github.hierynomus.license", version.ref = "license-plugin" }
nebula-integtest = { id = "nebula.integtest", version.ref = "nebula-integtest-plugin" }
build.gradle.kts
plugins {
id("java")
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.nebula.integtest)
alias(libs.plugins.jetbrains.intellij)
alias(libs.plugins.jetbrains.changelog)
alias(libs.plugins.hierynomus.license)
}
Note for accessing the catalog within scripts, please refer to the below section, the trick is the same.
Using convention plugins and included build
In the main project include a the Gradle project that holds the convention plugins.
build.gradle.kts
includeBuild("convention-plugins") // here it's a subfolder
convention-plugins/settings.gradle.kts
dependencyResolutionManagement {
repositories {
gradlePluginPortal()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "convention-plugins"
The trick to enable convention plugins to access the version catalog is split in two part, add an ugly implementation dependency that locate where the version catalog generated classes are located.
libs.javaClass.superclass.protectionDomain.codeSource.location
Then in the convention plugin refer to the libs extension via Project::the.
val libs = the<LibrariesForLibs>()
This is tracked by gradle/gradle#15383.
convention-plugins/build.gradle.kts
plugins {
`kotlin-dsl`
}
dependencies {
implementation(libs.gradleplugin.kotlin.jvm)
// https://github.com/gradle/gradle/issues/15383
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
}
And in the actual convention plugin
import org.gradle.accessors.dm.LibrariesForLibs
plugins {
id("org.jetbrains.kotlin.jvm")
}
// https://github.com/gradle/gradle/issues/15383
val libs = the<LibrariesForLibs>()
dependencies {
detektPlugins(libs.bundles.kotlinStuff) // access catalog entries
}
The org.gradle.accessors.dm.LibrariesForLibs class is generated by gradle is somewhere in local gradle folder ./gradle/<version>/dependency-accessors/<hash>/classes
Quick note that older IntelliJ IDEA currently (2022.3) reports alias(libs.gradleplugin.thePlugin) as an error in the editor,
although the dependencies are correctly resolved.
This tracked by KTIJ-19369, the ticket indicates this is actually a bug in Gradle Kotlin DSL gradle/gradle#22797, and someone made a simple IntelliJ IDEA plugin to hide this error until resolved.
Brice, it looks like a can of worms to go down that path, particularly for my situation, where I'm trying to use a libs.version.toml file from an android project, but the custom plugin is of course from a java/kotlin project. I tried creating the libs file by hardwiring the path to the toml file in the custom plugin. It might work if both were java projects, but I never tried that since that's not what I'm after. The ideal solution would be for the plugin to use the libs file from the project it is applied to, but it looks like the version catalog needs to be created in the settings file, before you even have access to "Project", so that's why you would have to hardwire the path.
Short answer. No, but there are other techniques for a custom plugin to get project version data from the project it is applied to.

Gradle cannot find prefix version transitive dependency which does not exist

I have a multi-module gradle project where in a module I add dependencies in compile configuration on runtime.
Those dependencies fetch a transitive dependency with a version prefix that does not exist.
So case is like this
compile 'group:moduleA:version.+'
This moduleA downloads moduleB with same version.+ prefix notation and that downloads another moduleC with same prefix notation, moduleC is present in artifactory with version 10 and above and 8 and below, so there are no versions which are number 9, and gradle insist on finding moduleC with version 9, it doesn't fetch versions above or below it.
How can I make gradle fetch another version if the version its trying to find is not there?
Please comment for any clarification and thanks for helping.
EDIT: Want to clarify that + in version part is not resolving to a number which is correct and present on artifactory, like 9.1 or 9.12.
gradle determines this version, which is incorrect like 9.1 is present but it resolves to 9.2 or some other number which is not there.
EDIT2: Task which is used to fetch dependencies and then add them in compile configuration.
task addAdditionalDependencies {
doLast {
Object slurper = new JsonSlurper().parseText(api.jsonResponse())
Set<String> dependencyNames = configurations.compile.dependencies.collect { it.name }
List<Map<String, String>> artifactPaths = slurper.results.collect {
String[] pathSegments = it.path.split('/')
if (!dependencyNames.contains(pathSegments[1]) && project.name != pathSegments[1]) {
[group: pathSegments[0],
name: pathSegments[1],
version: "version.+",
configuration: 'compile']
} else [:]
}
artifactPaths.each {
if (!it.isEmpty()) {
project.dependencies.add('compile', it)
}
}
// we have to call this because app does not have any source files and so compileJava does not download
// dependencies
configurations.compile.files
}
}
When using a version like 9.+, Gradle will looks for all version that matches the prefix, that is the part before the +.
There is however no way to make Gradle ignore that part in case no such version exist.
If the version of moduleC can be anything, then you could simply use + without any prefix.
Note that doing something like that could expose you to breakage in a build even though nothing changed, aside from a new version of moduleC being published.
You could also combine this dynamic version resolution with dependency locking to have a finer grained control on when to upgrade moduleC.

Gradle/Groovy refer to "file-wide/global" variable from inside block

In my build file I have the following line:
version = '1.1.2'
I want to make an executable "fat jar" using Shadow Jar (see my answer here) and then copy this to another directory (see answer here). But I want to incorporate the project's version number into the name of the jar file so as not to overwrite the existing version.
The Shadow Plugin User Guide explains how to set the name:
shadowJar {
baseName = 'shadow'
classifier = null
version = "7.7.7"
}
... but how might I set the variable version here to use the outer (file-wide/global...) variable version?
In a gradle script, there's a Project instance in scope which everything delegates to. When you say version = '1.1.2' it's actually invoking
getProject().setVersion('1.1.2')
In your shadowJar closure there's a version higher up in the scope which is hiding the project version. So you can do
shadowJar {
version = project.version
...
}

Resources