Using Artifactory matrix parameter queries at resolution time


(Francois Ritaly) #1

Is there a way to configure Gradle to use Artifactory’s support for matrix parameter queries at dependency resolution time ?

I want Gradle to lookup artifacts in Artifactory with a url like “https://artifactory/repository/com/acme/project/module/1.2.3/module-1.2.3.jar;property1=value1;property2=value2” (instead of “https://artifactory/repository/com/acme/project/module/1.2.3/module-1.2.3.jar”).

Those properties would typically be used to distinguish artifacts based on their associated promotion status. The resolution logic would return different artifacts based on the promotion status of the artifacts I need.

Note: According to the aforementioned page, I can easily tag my artifacts at publishing time with custom properties by using a custom url like “https://artifactory/repository/;property1=value;property2=value2”. I need a way to take into account those properties at resolution time now


(Francois Ritaly) #2

Actually what I need can be implemented by using a component selection rule


(Hoobajoob) #3

@Francois_Ritaly: We are trying to get the same thing done - could you describe how you use component selection rules to do this?

I’m finding that ComponentMetadata is really only aware of a property named status which (apparently) is assumed to be found in the descriptor file for the module (we have maven artifacts, so this would need to come from pom.xml, I believe). I can’t get it to look for arbitrary Artifactory properties, or I get an error that no such property exists.

If you’ve found a way to do this, it’d be fantastic if you could share!


(Francois Ritaly) #4

Sure, here’s the code (that was just a prototype so the code isn’t as clean as it should be).

I have a repository which hosts a bunch of artifacts in different versions. Those artifacts define a property “codeline” which denotes the branch the artifacts were built from. I wanted to check if Gradle could leverage the “codeline” property to resolve the correct artifacts based on the branch I want to compile against. Basically this is the same as defining a status for an artifact except that the status is defined via a meta-data instead of being hard-coded in an Ivy descriptor. The codeline actually denotes a promotion status and can be undefined or set to “trunk”, “rc”, “hotpatch”, “trunk;rc”, “trunk;rc;hotpatch”, “rc;hotpatch” (multi-values represent promotions of the artifacts: “trunk;rc” means the artifact was built from “trunk” then promoted to “rc”)

apply plugin: 'java'

// Defines the codeline attached to the artifacts we want to compile against
def requestedCodeline = 'rc' // 'trunk', 'rc', 'hotpatch'

println "Requested codeline: ${requestedCodeline}"

configurations {
    all {
        resolutionStrategy {
            componentSelection {
                all { ComponentSelection selection ->
                    // We need to determine if the given candidate relates to the codeline 
                    // we want to compile against

                    // We first need to identify the url of this artifact from its (group, module, version) identifier
                    def url1 = new URL("https://artifactory/api/search/gavc?g=${selection.candidate.group}&a=${selection.candidate.module}&v=${selection.candidate.version}&repos=artifactory-repository")
                    def json1 = url1.getText(requestProperties: [ 'Accept': 'application/json', 'Authorization': 'Basic ' + "${artifactory_user}:${artifactory_password}".getBytes().encodeBase64() ])

                    // Extract the artifact url from the JSON response
                    def url2 = new groovy.json.JsonSlurper().parseText(json1).results[0].uri

                    // Now query the artifact's properties
                    def url3 = new URL("${url2}?properties")
                    def json2 = url3.getText(requestProperties: [ 'Accept': 'application/json', 'Authorization': 'Basic ' + "${artifactory_user}:${artifactory_password}".getBytes().encodeBase64() ])

                    def json = new groovy.json.JsonSlurper().parseText(json2)

                    // What's the codeline associated to this artifact ? The property is a multi-value one (separator: semi-colon)
                    def codeline = json.properties.codeline

                    if (!codeline) {
                        selection.reject("No explicit codeline defined")

                        println "Rejected candidate '${selection.candidate}' because of missing property 'codeline'"
                    } else {
                        def codelines = codeline[0].split(';').collect { it.trim() }

                        if (codelines.contains(requestedCodeline)) {
                            println "Selected candidate '${selection.candidate}' with codelines ${codelines}"
                        } else {
                            println "Rejected candidate '${selection.candidate}' because of invalid codeline ${codelines}"

                            selection.reject("Invalid codeline")
                        }
                    }
                }
            }
        }
    }
}

dependencies {
    compile 'com.company.project:module:2.+'
}

With this trick, Gradle will select the correct artifact versions based on the associated ‘codeline’ property.

The build log looks like this

Requested codeline: rc
:clean
:compileJava
Rejected candidate 'com.company.project:module:2.3.1' because of missing property 'codeline'
Rejected candidate 'com.company.project:module:2.3.0' because of missing property 'codeline'
Rejected candidate 'com.company.project:module:2.2.1' because of missing property 'codeline'
Rejected candidate 'com.company.project:module:2.2.0' because of missing property 'codeline'
Rejected candidate 'com.company.project:module:2.1.118' because of invalid codeline [trunk]
Rejected candidate 'com.company.project:module:2.1.117' because of invalid codeline [trunk]
Rejected candidate 'com.company.project:module:2.1.116' because of invalid codeline [trunk]
Rejected candidate 'com.company.project:module:2.1.115' because of invalid codeline [trunk]
Rejected candidate 'com.company.project:module:2.1.114' because of invalid codeline [trunk]
Selected candidate 'com.company.project:module:2.1.113' with codelines [trunk, rc]
:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build
 
BUILD SUCCESSFUL
 
Total time: 14.146 secs

Hope that helps