Callum Rogers
04/22/2025, 3:15 PMConfiguration
? I really hoped something like
def sourceJars = configurations.register('sourceJars') {
extendsFrom otherConfiguration
attributes {
// but with the correct attribute
attribute LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, 'source-jar'
}
}
would just get me what I needed, rather than having to go through every jar then request the source jar using dependencies.createArtifactResolutionQuery()
for each main jar I find?Callum Rogers
04/22/2025, 3:17 PMoutgoingVariants
for my project does not give me hope this exists…Callum Rogers
04/22/2025, 3:27 PMdef sourceJarsBundle = configurations.register('sourceJarsBundle') {
extendsFrom configurations.mavenBundle
attributes {
attribute Category.CATEGORY_ATTRIBUTE, objects.named(Category.class, Category.DOCUMENTATION)
attribute DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, DocsType.SOURCES)
}
}
TrevJonez
04/22/2025, 4:21 PMCallum Rogers
04/22/2025, 4:50 PMCallum Rogers
04/22/2025, 4:51 PMCallum Rogers
04/22/2025, 5:12 PMTrevJonez
04/22/2025, 5:20 PMval unzipSources = target.tasks.register<UnzipperTask>("unzipTestCoverageSources") {
outDir.set(temporaryDir)
zips.from(
runtime.incoming.artifactView {
componentFilter { id -> id is ProjectComponentIdentifier }
withVariantReselection()
attributes {
attribute(USAGE_ATTRIBUTE, objects.named(JAVA_RUNTIME))
attribute(LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(JAR))
attribute(DOCS_TYPE_ATTRIBUTE, objects.named(DocsType.SOURCES))
attribute(CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION))
attribute(Attribute.of("org.gradle.jvm.environment", String::class.java), "standard-jvm")
attribute(Attribute.of("org.gradle.dependency.bundling", String::class.java), "external")
}
lenient(true)
}.files
)
}
val jvmClasses = runtime.incoming.artifactView {
componentFilter { id -> id is ProjectComponentIdentifier }
attributes {
attribute(USAGE_ATTRIBUTE, objects.named(JAVA_RUNTIME))
attribute(CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
attribute(LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(JAR))
}
lenient(true)
}
val unzipClasses = target.tasks.register<UnzipperTask>("unzipTestCoverageClasses") {
outDir.set(temporaryDir)
zips.from(jvmClasses.files)
}
then for android sub projects
val unzipSourcesTaskName = "unzip${variant.name.capitalized()}CoverageSources"
val unzipSources = runCatching { target.tasks.named<UnzipperTask>(unzipSourcesTaskName) }
.getOrElse {
target.tasks.register<UnzipperTask>("unzip${variant.name.capitalized()}CoverageSources") {
outDir.set(temporaryDir)
zips.from(
variant.runtimeConfiguration.incoming.artifactView {
componentFilter { id -> id is ProjectComponentIdentifier }
withVariantReselection()
attributes {
attribute(USAGE_ATTRIBUTE, objects.named(JAVA_RUNTIME))
attribute(LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(JAR))
attribute(DOCS_TYPE_ATTRIBUTE, objects.named(DocsType.SOURCES))
attribute(CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION))
variant.buildType?.let { buildType ->
attribute(BuildTypeAttr.ATTRIBUTE, objects.named(buildType))
}
variant.productFlavors.forEach { (dimen, flavor) ->
attribute(ProductFlavorAttr.of(dimen), objects.named(flavor))
}
}
lenient(true)
}.files
)
zips.from(
variant.runtimeConfiguration.incoming.artifactView {
componentFilter { id -> id is ProjectComponentIdentifier }
withVariantReselection()
attributes {
attribute(USAGE_ATTRIBUTE, objects.named(JAVA_RUNTIME))
attribute(LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(JAR))
attribute(DOCS_TYPE_ATTRIBUTE, objects.named(DocsType.SOURCES))
attribute(CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION))
attribute(Attribute.of("org.gradle.jvm.environment", String::class.java), "standard-jvm")
attribute(Attribute.of("org.gradle.dependency.bundling", String::class.java), "external")
}
lenient(true)
}.files
)
}
}
val classesConfigName = "projectClasses${variant.name.capitalized()}"
val classesConfig =
runCatching {
target.configurations.named(classesConfigName)
}.getOrElse {
target.configurations.resolvable(classesConfigName) {
extendsFrom(variant.runtimeConfiguration)
attributes {
attribute(USAGE_ATTRIBUTE, objects.named(JAVA_RUNTIME))
attribute(CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
variant.buildType?.let { buildType ->
attribute(BuildTypeAttr.ATTRIBUTE, objects.named(buildType))
}
variant.productFlavors.forEach { (dimen, flavor) ->
attribute(ProductFlavorAttr.of(dimen), objects.named(flavor))
}
}
}
}
val androidClasses = classesConfig.get().incoming.artifactView {
componentFilter { id -> id is ProjectComponentIdentifier }
attributes {
attribute(AndroidArtifacts.ARTIFACT_TYPE, AndroidArtifacts.ArtifactType.CLASSES_JAR.type)
}
lenient(true)
}
val jvmClasses = classesConfig.get().incoming.artifactView {
componentFilter { id -> id is ProjectComponentIdentifier }
attributes {
attribute(USAGE_ATTRIBUTE, objects.named(JAVA_RUNTIME))
attribute(LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(JAR))
}
lenient(true)
}
val unzipClassesName = "unzip${variant.name.capitalized()}CoverageClasses"
val unzipClasses = runCatching {
target.tasks.named<UnzipperTask>(unzipClassesName)
}.getOrElse {
target.tasks.register<UnzipperTask>(unzipClassesName) {
outDir.set(temporaryDir)
zips.from(androidClasses.files)
zips.from(jvmClasses.files)
}
}
TrevJonez
04/22/2025, 5:21 PMval sources = target.tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
from(
kotlinJvmExt
.sourceSets
.named<KotlinSourceSet>("main")
.get()
.kotlin
) {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
into("main")
}
target.pluginManager.withPlugin("org.gradle.java-test-fixtures") {
from(
kotlinJvmExt
.sourceSets
.named<KotlinSourceSet>("testFixtures")
.get()
.kotlin
) {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
into("testFixtures")
}
}
}
val objects = target.objects
target.configurations.consumable("sourceElements") {
isVisible = false
attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR))
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType.SOURCES))
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION))
attribute(Attribute.of("org.gradle.jvm.environment", String::class.java), "standard-jvm")
attribute(Attribute.of("org.gradle.dependency.bundling", String::class.java), "external")
}
outgoing.artifact(sources) {
type = ArtifactTypeDefinition.JAR_TYPE
}
}
Vampire
04/22/2025, 8:20 PMwithSourcesJar()
which would configure that variant, but it's a manual artifact(sourcesJar)
call on the publication, it will also not work.
For those (both cases) you would then have to use a component metadata rule to add the missing sources variant, then it should probably work for all.TrevJonez
04/22/2025, 9:31 PMkotlin("jvm")
modulesTrevJonez
04/22/2025, 9:32 PMCallum Rogers
04/23/2025, 1:40 PMsources
jar file to
2. For local project deps, I can apply a plugin on every project that will make a new variant/Configuration with an artifact being the output of the sourcesJar
task with the same attribute
3. Resolve using an artifact view on the relevant Configuration giving my attributeCallum Rogers
04/23/2025, 1:45 PMpublic static final class SourceJarForMavenBundling implements ComponentMetadataRule {
@Override
public void execute(ComponentMetadataContext context) {
context.getDetails().addVariant("sourceJarForMavenBundling", variantMetadata -> {
variantMetadata.getAttributes().attribute(MAVEN_BUNDLE_SOURCE_JAR, true);
variantMetadata.withFiles(
files -> files.addFile(context.getDetails().getId().getName() + "-"
+ context.getDetails().getId().getVersion() + "-sources.jar"));
});
}
}
project.getDependencies().getComponents().all(SourceJarForMavenBundling.class);
mavenBundleConfiguration
.getIncoming()
.artifactView(av -> {
av.attributes(attrs -> {
attrs.attribute(MAVEN_BUNDLE_SOURCE_JAR, true);
});
})
.getFiles()
.getFiles(); // no files
Callum Rogers
04/23/2025, 1:46 PMTrevJonez
04/23/2025, 2:03 PMVampire
04/23/2025, 2:05 PMwithSourcesJar
for your projects so that for your projects the variant is properly set up, and in the component metadata rule add a variant that is set up like the one added by withSourcesJar
.
Then you can use those standard attributes to resolve them.Callum Rogers
04/23/2025, 2:30 PMwithSourcesJar
). Likely we’re doing something odd thoughCallum Rogers
04/23/2025, 2:30 PM./gradlew :project:outgoingVariants
Vampire
04/23/2025, 2:36 PM