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
1 Like
Actually what I need can be implemented by using a component selection rule
@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!
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