Snapshot dependency resolution

As part of learning Gradle, I created a Jenkins job to automatically compile and run tests against java source that is uploaded.

  1. Job 1 accepts the upload of source code, does a little sanity checking on the file structure, and pushes it as a maven artifact to an artifactory instance via the Jenkins artifactory plugin 2. Job 2 retrieves the maven artifact of the source code, compiles it, and pushes the compiled jars as a maven artifact 3. Job 3 retrieves the maven artifact of the compiled code and runs tests against it

All jobs are parameterized to accept a variable called ‘candidateName’. This variable is used to set ‘archivesBaseName’ (which I also use as my maven artifactId).

I’m seeing some odd behavior if I don’t tell Gradle to invalidate its cache (’–refresh-dependencies’). This is what’s happening:

  1. Run job 1 with buggy source code under ‘candidateName=foo’. The artifact in artifactory contains the expected buggy source code. 2. Job 2 is triggered by job 1. It produces a jar with the compiled classes. The artifact in artifactory contains the expected buggy classes. 3. Job 3 is triggered by job 2. The tests catch the bug and flag the run as failed. 4. Re-run job 1 with patched source code under ‘candidateName=foo’ (the desire is to track/store/build multiple submission attempts). The artifact in artifactory contains the expected patched source code. 5. Job 2 is triggered by job 1. The jar it produces contains classes that are identical to those from step 2. 6. Job 3 is triggered by job 2 and fails because the classes it’s executing are identical to those from step 2 and 3.

It looks like after the initial runs of jobs 2 and 3, Gradle believes the snapshot copies of the source and compiled artifacts in the local cache are up to date.

Log snippet from the initial run of job 2 (gradle [correctly] retrieves the snapshot artifact from artifactory): ‘’’’ 13:34:48.788 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on artifact cache (/home/jenkins/.gradle/caches/artifacts-23). 13:34:48.788 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired. 13:34:48.790 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Opening cache artifact-at-repository.bin (/home/jenkins/.gradle/caches/artifacts-23/artifact-at-repository.bin) 13:34:48.791 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache artifact-at-repository.bin (/home/jenkins/.gradle/caches/artifacts-23/artifact-at-repository.bin) 13:34:48.791 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/home/jenkins/.gradle/caches/artifacts-23). 13:34:48.792 [DEBUG] [org.gradle.api.internal.artifacts.repositories.resolver.ExternalResourceResolver] Loading http://localhost:8081/artifactory/quizmaster/com/bar/foo-raw/1.0-SNAPSHOT/foo-raw-1.0-20130423.203427-1.jar … 13:34:48.803 [DEBUG] [org.apache.http.headers] << X-Checksum-Sha1: 66eb3dc418df30c2b8b780a476c469ab3b4eda17 13:34:48.803 [DEBUG] [org.apache.http.headers] << X-Checksum-Md5: 32eaf82d5342f716927425ba1a84c95a … 13:34:48.805 [DEBUG] [org.gradle.api.internal.externalresource.transport.http.HttpResponseResource] Attempting to download resource http://localhost:8081/artifactory/quizmaster/com/bar/foo-raw/1.0-SNAPSHOT/foo-raw-1.0-20130423.203427-1.jar. … 13:34:48.809 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on artifact cache (/home/jenkins/.gradle/caches/artifacts-23). 13:34:48.809 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired. 13:34:48.809 [DEBUG] [org.gradle.api.internal.artifacts.ivyservice.ivyresolve.CachingModuleVersionRepository] Downloaded artifact ‘com.bar#foo-raw;1.0-SNAPSHOT!foo-raw.jar’ from resolver: org.gradle.api.internal.artifacts.ivyservice.ivyresolve.CacheLockingModuleVersionRepository@7d61802a 13:34:48.810 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Opening cache artifact-at-repository.bin (/home/jenkins/.gradle/caches/artifacts-23/artifact-at-repository.bin) 13:34:48.810 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache artifact-at-repository.bin (/home/jenkins/.gradle/caches/artifacts-23/artifact-at-repository.bin) 13:34:48.810 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/home/jenkins/.gradle/caches/artifacts-23). … 13:34:49.383 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on artifact cache (/home/jenkins/.gradle/caches/artifacts-23). 13:34:49.383 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired. 13:34:49.383 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/home/jenkins/.gradle/caches/artifacts-23). 13:34:49.396 [QUIET] [system.out] Extracting: /home/jenkins/.gradle/caches/artifacts-23/filestore/com.bar/foo-raw/1.0-SNAPSHOT/jar/66eb3dc418df30c2b8b780a476c469ab3b4eda17/foo-raw-1.0-SNAPSHOT.jar to /home/jenkins/.jenkins/jobs/compile/workspace/candidate ‘’’’

Log snippet from the second run of job 2 (gradle does not retrieve the updated snapshot artifact from artifactory): ‘’’’ 13:35:50.225 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on artifact cache (/home/jenkins/.gradle/caches/artifacts-23). 13:35:50.225 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired. 13:35:50.228 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Opening cache artifact-at-repository.bin (/home/jenkins/.gradle/caches/artifacts-23/artifact-at-repository.bin) 13:35:50.230 [DEBUG] [org.gradle.api.internal.artifacts.ivyservice.ivyresolve.CachingModuleVersionRepository] Found artifact ‘com.bar#foo-raw;1.0-SNAPSHOT!foo-raw.jar’ in resolver cache: /home/jenkins/.gradle/caches/artifacts-23/filestore/com.bar/foo-raw/1.0-SNAPSHOT/jar/66eb3dc418df30c2b8b780a476c469ab3b4eda17/foo-raw-1.0-SNAPSHOT.jar 13:35:50.230 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache artifact-at-repository.bin (/home/jenkins/.gradle/caches/artifacts-23/artifact-at-repository.bin) 13:35:50.230 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/home/jenkins/.gradle/caches/artifacts-23). 13:35:50.231 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire shared lock on no_buildscript class cache for build file ‘/home/jenkins/.jenkins/jobs/compile/workspace/build/build.gradle’ (/home/jenkins/.gradle/caches/1.5/scripts/build_326ve2qn76pmhsph0k3q158ud9/ProjectScript/no_buildscript). 13:35:50.232 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired. 13:35:50.337 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on artifact cache (/home/jenkins/.gradle/caches/artifacts-23). 13:35:50.337 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired. 13:35:50.338 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/home/jenkins/.gradle/caches/artifacts-23). 13:35:50.352 [QUIET] [system.out] Extracting: /home/jenkins/.gradle/caches/artifacts-23/filestore/com.bar/foo-raw/1.0-SNAPSHOT/jar/66eb3dc418df30c2b8b780a476c469ab3b4eda17/foo-raw-1.0-SNAPSHOT.jar to /home/jenkins/.jenkins/jobs/compile/workspace/candidate ‘’’’

Is there a bug in Gradle’s dependency resolution?

Additional notes:

  1. Gradle 1.5 2. Artifactory Plugin 2.1.2

By default, snapshot dependencies are cached for 24 hours. See the Gradle User Guide for how to configure the cache timeout interval.

Looking through the docs I’m a little fuzzy on the difference between ‘resolutionStrategy.cacheDynamicVersionsFor’ and ‘resolutionStrategy.cacheChangingModulesFor’. I’m guessing that snapshot dependencies fall under dynamic versions. Is this correct?

Just ran a quick test. Looks like I had it reversed. Snapshot dependencies are controlled by ‘resolutionStrategy.cacheChangingModulesFor’

Currently snapshots are modeled as changing modules, but there is a plan to eventually model them as dynamic versions.