When publishing snapshots to artifactory/mavenLocal, projects won't pick up the latest snapshot. This requires deleting the jar from ~/.gradle/cache
Maven has a feature to set timestamps for snapshots. how would this work with gradle cache?
There are two things to consider in resolving your issue:
How Gradle handles/recognizes snapshots
How to override Gradle's default behavior
Some background on how Gradle recognizes/handles snapshots
By default, Gradle will refresh a snapshot dependency every 24 hours.
Gradle will automatically recognize a dependency as a snapshot if the version ends with the -SNAPSHOT suffix. For example:
dependencies {
compile group: "aGroup", name: "anArtifact", version: "1.0-SNAPSHOT"
}
However, if the dependency's version string does not end with -SNAPSHOT Gradle needs to be told it's a snapshot with the changing parameter. For example:
dependencies {
compile group: "aGroup", name: "anArtifact", version: "1.0", changing: true
}
Overriding how often Gradle downloads snapshots
The only mechanism for overriding the default 24 hour policy is to configure Gradle to invalidate dependency cache (and thus download a new SNAPSHOT) more frequently. For example:
configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}
Dynamically versioned dependency cache will need to be configured separately
If you're using any dynamic versions, such as:
dependencies {
compile group: "aGroup", name: "anArtifact", version: "1.+", changing: true
}
You'll need to configure cache invalidation for those dependencies separately, like this:
configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
resolutionStrategy.cacheDynamicVersionsFor 0, 'seconds'
}
Build performance impact
One thing to note is that the shorter the period of time a dependency is cached the more frequently Gradle will retrieve that artifact. If caching is disabled altogether, it will grab the dependency during each execution.
Related
I have a project with 3 common jars shared across multiple repositories. I'm using Intellij 2019.4. In my gradle build, I included the following method:
dependencyManagement {
resolutionStrategy {
// don't cache SNAPSHOT modules; always retrieve them from the maven cache
cacheChangingModulesFor 0, 'seconds'
}
}
That's supposed to tell Gradle not to cache snapshots, but mine are still being cached. I build and install one of the common jars, and the maven repo has it, but the Gradle cache still has a jar from over 24 hours ago. Is there a different method I should be using? I want Gradle to ALWAYS use what's in the .m2 repo.
Gradle will only search for modules in the declared repositories.
This means that if you need a library, SNAPSHOT or not, from you local Maven repository, you need to declare it as a repository in Gradle.
repositories {
mavenLocal() {
content {
includeModule("my.org", "someLib")
}
}
// other repositories
}
However, there are caveats in adding mavenLocal() to your repositories, so make sure to use repository content filtering to only search your local Maven repo for those SNAPSHOT dependencies, as shown above.
Try to add changing = true into individual SNAPSHOT dependencies' configClosure.
implementation("group:module:1.0-SNAPSHOT") {changing = true}
Then cacheChangingModulesFor should apply to them:
configurations.all() {
resolutionStrategy {
cacheChangingModulesFor 0, "seconds"
}
}
With version latest.integration, this would require the build-number added into the version - but, this would keep the build reproducible, since one can switch back to the previous build of the library.
There also is a CLI option --refresh-dependencies, which refreshes them all.
The Gradle manual explains it, too: Declaring a changing version.
Forcibly deleting them before build would be another option.
I store library artifacts after compilation with Gradle in an internal Artifactory repository that is not accessible from the Internet. When I'm working offline or outside the company, I cannot access that repository.
One application ("web-application") that uses such libraries has configured the following settings in build.gradle:
...
repositories {
mavenCentral()
maven {
url "https://artifactory.company.com"
}
}
...
dependencies {
compile(group: 'com.company', name: 'common-lib', version: '1.0.+', changing: true)
}
...
dependencyManagement {
}
resolutionStrategy {
cacheChangingModulesFor 0, 'seconds'
cacheDynamicVersionsFor 0, 'seconds'
}
}
This works fine for CI/CD and when I am in the office. It ensures the most recent bugfix-version of a library is used so not every project has to be touched whenever there is a bump of the bugfix counter.
To work offline, I came across the Composite Build feature of Gradle: https://docs.gradle.org/current/userguide/composite_builds.html
This way, I can check-out the code locally and add those settings:
web-application/settings.gradle
rootProject.name='web-application'
includeBuild '../common-lib'
common-lib/settings.gradle
rootProject.name='common-lib'
In addition, I have to remove the dependency in web-application/build.gradle:
dependencies {
/* compile(group: 'com.company', name: 'common-lib', version: '1.0.+', changing: true) */
}
Lastly, IntelliJ IDEA asks me whether to add a dependency on the module common-lib, which I accept. This works fine but then again, I can't commit the changes in build.gradle as this would break CI/CD pipelines that rely on checked-in libraries.
What is the correct way to make both scenarios work?
My build.gradle references a local maven pom. I have enabled the mavenLocal() repository and have added the jar as a compile time dependency (eg. my-local-lib, as shown below).
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
compile (group: 'com.company', name: 'my-local-lib', version: '1.0-SNAPSHOT')
}
Gradle indeed picks it up and adds it as a dependency. My-local-lib, however, is itself dependent on another library as specified in its pom.xml, but gradle fails to pick up the correct version specified in the pom.xml, and instead chooses a much earlier version. This particular jar dependency is not a dependency on any other library.
Is this a known issue? Could it be due to my-local-lib being a SNAPSHOT version? Is there a way that I can enforce gradle to respect the versions specified in the libraries?
Try to add the following piece of code:
configurations.all {
resolutionStrategy {
cacheChangingModulesFor 0, 'seconds'
}
}
to build.gradle script.
I have project A and B. Project B depends on A.
If I build a snapshot for B, it will trigger a snapshot build on A. The issue is that when the latest snapshot of A gets pushed, B doesn't pick up the latest snapshot. Rather, it picks up the one before that.
Is there any reason why? And can I pull the latest snapshot every time ?
If your dependencies do not have the "-SNAPSHOT", you can specifically tell gradle that the dependency is a changing one like this:
dependencies {
compile group: "group", name: "artifact", version: "1.0", changing: true
}
However even changing dependencies are cached for 24 hours by default. To make sure you will always get the latest one, use:
configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}
We have a custom gradle plugin, which is applied to all the projects we have. Since the plugin is released every several days, I don't want to update all the codebase to change it to use the latest version of the plugin.
How to declare it in gradle to ask it always get the latest version of the dependency?
I tried:
dependencies {
classpath "com:my-plugin:[1.0.0,)"
}
or
dependencies {
classpath "com:my-plugin:+"
}
They can get the latest version the first time, but won't get the newer one again.
as a default, once gradle resolved a dynamic dependency, gradle won't check for newer versions for 24h. you have different options to influence this. one option is to run your build with --refresh-dependencies or you customize the TTL in your build script. E.g:
configurations.all {
resolutionStrategy.cacheDynamicVersionsFor 10, 'minutes'
}
The following script should do the job:
apply plugin: 'java'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.google.inject:guice:latest.release'
}
}
Check out the docs here.
Another option is to go for snapshot publishing and configure dependency resolver to check seconds if the library changes so often.