Is it possible to substitute a project dependency with its outgoing artifacts?

Hello,

I question myself regarding gradle way of handling variants and artifacts. Is it possible to generate a BOM featuring 2 dependencies, the foo and bar variants produced by a subproject?

So far I was not able to achieve this…

Given a multi-project initialized with:

allprojects {
    apply plugin: 'base' // for clean, assemble tasks
}

subprojects {
    apply plugin: 'maven-publish'
    group = 'org.example'
    version = '3.1415'

    publishing {
        repositories {
            maven {
                name = 'temp'
                url rootProject.layout.buildDirectory.dir("repo")
            }
        }
    }
}

And a subproject that generate several outgoing artifacts (think of each one being a zip file containing configuration files for specific target environments) with:

// producer/build.gradle

// This is a truncated binary plugin copied in a quick and dirty way to
// highlight its main features (and because SoftwareComponentFactory cannot be
// used directly from scripts)
class MultipleArtifactsPlugin implements Plugin<Project> {

    def component

    @javax.inject.Inject MultipleArtifactsPlugin(SoftwareComponentFactory factory) {
        component = factory.adhoc("outgoing");
    }   

    @Override void apply(Project p) {
        p.components.add component
        def conf = p.configurations.create("outgoingElements") {
            canBeResolved = false
            canBeConsumed = true
            attributes {
                attribute(Usage.USAGE_ATTRIBUTE, p.objects.named(Usage, Usage.JAVA_RUNTIME))
                attribute(Category.CATEGORY_ATTRIBUTE, p.objects.named(Category, Category.LIBRARY))
            }   
        }   
        component.addVariantsFromConfiguration(conf) { mapToMavenScope("runtime") }
    }   
}   

apply plugin: MultipleArtifactsPlugin

def foo = tasks.register("foo", Zip) {
    from("foo")
    archiveFileName = "${project.name}-${project.version}-foo.zip"
    archiveClassifier = "foo"
    destinationDirectory = layout.buildDirectory.dir("outgoing")
}   

def bar = tasks.register("bar", Zip) {
    from("bar")
    archiveFileName = "${project.name}-${project.version}-bar.zip"
    archiveClassifier = "bar"
    destinationDirectory = layout.buildDirectory.dir("outgoing")
}   

configurations.outgoingElements {
    outgoing {
        artifact(foo)
        artifact(bar)
    }   
}   

tasks.named("assemble").configure {
    dependsOn(foo, bar)
}   

publishing {
    publications {
        maven(MavenPublication) {
            afterEvaluate {
                from(components["outgoing"])
            }   
        }   
    }   
}

When I want to publish a BOM listing all the generated artifacts with:

plugins {
	id 'java-platform'
}

javaPlatform {
	allowDependencies()
}

dependencies {
	runtime project(':producer')
}

publishing {
	publications {
		maven(MavenPublication) {
			from(components["javaPlatform"])
		}
	}
}

tasks.register("listArtifacts") {
	inputs.files configurations.classpath
	doLast  {
		inputs.files.collect { it.absolutePath }.each { println it }
	}
}

And the command gradle clean [listArtifacts] publish

Then:

foo and bar artifacts from producer are published on the maven repository
foo and bar artifacts from producer can be consumed in consumer (listArtifacts shows them)
the BOM for the consumer project is published on the maven repository
the BOM lacks dependencies on the producer foo and bar artifacts which is desired, instead I have a useless dependency on the project consumer

Use of maven-publish plugin and maven BOM is required because clients of this BOM are almost exclusively maven builds.

Thanks for your inputs.

To answer myself, it seems that the following hack can do the trick:

// consumer/build.gradle

publishing {
	publications {
		maven(MavenPublication) {
			pom.withXml {
				def dependenciesNode = asNode().appendNode('dependencies')

				configurations.classpath.resolvedConfiguration.resolvedArtifacts.each {
					def id = it.moduleVersion.id
					def dependencyNode = dependenciesNode.appendNode('dependency')
					dependencyNode.appendNode('groupId', id.group)
					dependencyNode.appendNode('artifactId', id.name)
					dependencyNode.appendNode('version', id.version)
					dependencyNode.appendNode('scope', 'runtime')
					if (it.classifier) {
						dependencyNode.appendNode('classifier', it.classifier)
					}
					if (it.type) {
						dependencyNode.appendNode('type', it.type)
					}
				}
			}
		}
	}
}

So I’ll change my question to, is there any way to achieve the same result with a DSL option somewhere in the variant selection/transformation API ?

Thanks a lot