[Feedback needed] Gradle Module Metadata

Hi folks,

I’m starting this thread to gather feedback about Gradle Module Metadata, which ships 1.0 in Gradle 5.3.

We’re looking for early adopters, both on the library authors side (you build a library, and you’d like to publish Gradle Module Metadata) and as a consumer of module metadata.

Feel free to ask questions here, this thread might be split into specific discussions as needed.

Thanks a lot!

Looks like a very nice feature that would also help with managing elaborate custom details about published artifacts at the dependency management level!

However, I’m afraid I need a leg up on how to try this out. In a data project, I did this:

  1. I upgrade my Gradle wrapper to 5.3-rc-3
  2. I appended enableFeaturePreview("GRADLE_METADATA") to my settings.gradle
  3. I ran ./gradlew publish, but could not find any *.module files in the target repository

Inspecting this further, I ran ./gradlew generatePomFileForMavenPublication and see this output:

> Task :generateMetadataFileForMavenPublication SKIPPED
Maven publication 'maven' isn't attached to a component. Gradle metadata only supports publications with software components (e.g. from component.java)

My project only uses the ‘base’ and ‘maven-publish’ plugins, and the ‘default’ artifact is just a Zip task:

task packageRefPitch(type: Zip) {
    from extractData.refDir
    classifier 'reference'
}

artifacts {
    'default' packageRefPitch
}

publishing {
    publications {
        maven(MavenPublication) {
            artifact packageRefPitch
        }
    }
    repositories {
        maven {
            url "$buildDir/repo"
        }
    }
}

How can I publish a Gradle .module file with some custom metadata? If that doesn’t work directly, how can I register the ‘default’ artifact of my data project as a component?

The error message says it all:

Maven publication 'maven' isn't attached to a component. Gradle metadata only supports publications with software components (e.g. from component.java)

You must have a software component, so that Gradle understands the semantics of your module (that’s what Gradle Module Metadata is about). So you need something like:

from components.java

adhoc artifacts are by definition out of context :slight_smile:

Is it planned to support ad-hoc artifacts? Or do I have to find a way to register my custom artifact as a component? (I tried that some time ago, but gave up without finding a solution. Any pointers would be much appreciated!)

1 Like

The whole idea is that there are no adhoc artifacts. Artifacts are attached to variants. And yes there’s an API for that, using SoftwareComponentFactory. The Java plugins uses this API to declare custom components.

Thanks very much for the prompt and helpful replies! I’ll see what I can come with and open a different discussion if necessary.

Is there a public API to create (and hopefully publish) the metadata outside build scripts?

My use case: I develop a Gradle plugin that facilitates software development for an environment that includes a lot of JARs not available in any repositories by default. So the plugin must be able to publish artifacts in a repository without making corresponding publications part of a project it applied to.

Currently I use org.eclipse.aether to publish these artifacts along with Maven POM metadata but Gradle Metadata looks much more suitable for this (considering complex relationships between the artifacts) so I’d like to try it.

No, currently only Gradle is capable of generating and publishing Gradle Module Metadata. One reason being that we generate it from our model (components.java, …) so we don’t need this, but it would be worth extracting a library from the writer.

org.gradle.jvm.version

Only allows a minimum java version.

It should support a more verbose version syntax, presumably the one used by build scripts for dependencies.

That would be useful for modules that don’t yet support newer versions of java (as many projects don’t yet support 9, 10, 11, or 12), and for ones that use APIs / features that have been removed from newer or future versions of java.

This would help devs quickly determine the latest java they can use, and help pinpoint roadblock projects.

The org.gradle.jvm.version is NOT a version constraint. The only thing it says is “if you try to use it on a VM that doesn’t support this version, this is going to fail”. You can have different variants with higher levels, but it’s not mandatory. All you explain is that if you have different variants, Gradle can choose the most appropriate (closest match).

It would be useful if org.gradle.jvm.version was changed to be a version constraint.

Great work on the metadata system!

I’ve been busy adding it to one of my pet projects. I specify some of my dependencies in ranges, e.g. [1.0,2.0[
This empowers Gradle to pick the most fitting version depending on the transitive dependencies of my dependencies, etc. Works awesomely!

Now, I want to publish my version ranges as the “required” version so that consuming projects can, too, empowered by Gradle pick the best fitting version - this works like a charm when enabling the metadata preview flag.

Now additionally, I want to publish the version that was actually resolved during the build of my project as a “preferred” version (since thats what the tests ran against, etc).

I’m using Gradle dependency locking, so I do not have the concrete version hardcoded anywhere in the build.gradle.

How do I achieve publishing the concrete resolved version as a prefered version?

The module.json should look something like:

{
  "group": "org.slf4j",
  "module": "slf4j-api",
  "version": {
    "requires": "[1.0,2.0[",  <-- this is already there, awesome
    "prefers": "1.7.28"        <-- this is currently missing, the version is available from lock files
  }
}

Best,
Napster

Hi @CedricChampeau,

I’d like very much to be one of those adopter (on library author side), especially in the context of having a jdk 8 and 9+ variance awareness

But I didn’t really understood what shall be done in order to implement it, neither I managed to get some help on SO or here

Could you please give me some inputs how to implement it?

Also, I’m using Jitpack, would that be a problem?

Please also consider support for metadata information of dependency declarations that can be used for authenticating the same. This could either be a hash, if it is a strict dependency, or the OpenPGP key fingerprint(s) expected to sign the dependency (in case of a dependency declared via dynamic/ranged version specifier).

See also: MNG-6026: Extend the Project Object Model (POM) with trust information (OpenPGP, hash values)

It’s a struggle. Why can’t it be simpler?
Such as, I’m putting together a publication, I enumerate the artifacts (jars), and the metadata automatically generates (with some defaults that I can tweak). Done.

The whole “component” thing ties everything together. And requires authoring a plugin, as you can’t create a component ad-hoc? For most people there is only one component, “java”, the default one. Make metadata publishing available for those people.

What are you talking about? Metadata is available for “those people” and even enabled by default already.

Sorry didn’t express myself well. I was planning to write a separate post detailing my ordeal in customizing publishing for a multi-variant artifact to 2 different repos. In short, it is next to impossible even with days of research.

So: say you’ve got the .jar, -sources.jar, -javadoc.jar and even an -all.jar published to a repo, yes that works through the java component.
But what if you want a subset of these jars going to a different repo? Say all except the main jar. You can’t do it.
I would like the ability to enumerate the variants/configurations to publish to Repo1, and separately those that go to Repo2, and metadata to be generated automatically for both. This is currently not possible.