Search code examples
gradledependenciesnexus-iq

Copy all Gradle dependencies without pre-registered custom task


Use Case

The use case for grabbing all dependencies (without the definition of a custom task in build.gradle) is to perform policy violation and vulnerability analysis on each of them via a templated pipeline. We are using Nexus IQ to do the evaluation.

Example

This can be done simply with Maven, by specifying the local repository to download all dependencies and then supply a pattern to Nexus IQ to scan. In the example below we would supply maven-dependencies/* as the scan target to Nexus IQ after rounding up all the dependencies.

mvn -B clean verify -Dmaven.repo.local=${WORKSPACE}/maven-dependencies

In order to do something similar in Gradle it seems the most popular method is to introduce a custom task into build.gradle. I'd prefer to do this in a way that doesn't require developers to implement custom tasks; it's preferred to keep those files as clean as possible. Here's one way I thought of making this happen:

  1. Set GRADLE_USER_HOME to ${WORKSPACE}/gradle-user-home.
  2. Run find ${WORKSPACE}/gradle-user-home -type f -wholename '*/caches/modules*/files*/**/*.*' to grab the location of all dependency resources (I'm fine with picking up non-archive files).
  3. Copying all files from step #1 to a gradle-dependencies folder.
  4. Supply gradle-dependencies/* as the scan target to Nexus IQ.

Results

I'm super leery about doing it this way, as it seems very hacky and doesn't seem like the most sustainable solution. Is there another way that I should consider?


UPDATE #1: I've adjusted my question to allow answers that have custom tasks, just not pre-registered. Pre-registered means the custom task is already in the build.gradle file. I'll also provide my answer shortly after this update.


Solution

  • I'm uncertain if Gradle has the ability to register external, custom tasks, but this is how I'm making ends meet. I've created a custom task in a file called copyAllDependencies.gradle, appending the contents of that file (after replacing all newlines and instances of two or more spaces with a single space) to build.gradle when the pipeline runs, and then running gradlew copyAllDependencies. I then pass gradle-dependencies/* as the scan target to Nexus IQ.

    task copyAllDependencies(type: Copy) {
        def allConfigurations = [];
        configurations.each {
            if (it.canBeResolved) {
                allConfigurations += configurations."${it.name}"
            }
        };
        from allConfigurations
        into "gradle-dependencies"
    }
    

    I can't help but feel that this isn't the most elegant solution, but it suits my needs for now.


    UPDATE #1: Ultimately, I decided to go with requiring development teams to specify this custom task in their build.gradle file. There were too many nuances with echoing script contents into another file (hence the need to include ; when defining allConfigurations and iterating over all configurations). However, I am still open answers that address the original question.