Quantcast
Channel: Gradle Forums - Latest posts
Viewing all articles
Browse latest Browse all 19888

Why do WARs have no dependencies with maven-publish

$
0
0

Hello @jendrik,

I’ve had some closer look at the custom software component configuration for our plugin, That’s what I ended up with.

The easiest part was the configuration of the adhoc component:

    private void createSoftwareComponent(final Project project) {
        project.getConfigurations().getByName(WarPlugin.PROVIDED_COMPILE_CONFIGURATION_NAME).getArtifacts().add(artifact);
        // create an adhoc component
        AdhocComponentWithVariants component = softwareComponentFactory.adhoc(SOFTWARE_COMPONENT_NAME);
        // and register configuration variants for publication
        //component.addVariantsFromConfiguration(project.getConfigurations().getByName(WarPlugin.PROVIDED_COMPILE_CONFIGURATION_NAME), new JavaConfigurationVariantMapping("provided", false));
        //component.addVariantsFromConfiguration(project.getConfigurations().getByName(WarPlugin.PROVIDED_RUNTIME_CONFIGURATION_NAME), new JavaConfigurationVariantMapping("provided", false));
        component.addVariantsFromConfiguration(project.getConfigurations().getByName(WarPlugin.PROVIDED_COMPILE_CONFIGURATION_NAME), new JavaConfigurationVariantMapping("compile", false));
        component.addVariantsFromConfiguration(project.getConfigurations().getByName(WarPlugin.PROVIDED_RUNTIME_CONFIGURATION_NAME), new JavaConfigurationVariantMapping("runtime", false));
        // add it to the list of components that this project declares
        project.getComponents().add(component);
    }

Still there are two things that caught my attention. First the maven configuration provided cannot be targeted (see the commented out lines) as this throws the following error:
> Invalid Maven scope 'provided'. You must choose between 'compile' and 'runtime'

So I’ve switched to compile and runtime but I’m not sure this limitation will make everyone happy, as it also aktively prevents the generation of backward compatible pom files (the maven plugin produced these scopes).

With that in place the pom.xml actually looked promising but no artifact was deployed. First I simply added the artifact to the publication, but I guess that’s not how it is supposed to work.

    private void configurePublishing(Project project) {
        final PublishingExtension publishingExt = project.getExtensions().getByType(PublishingExtension.class);
        final MavenPublication mavenPublication = publishingExt.getPublications().maybeCreate(MyProjectUtils.PUBLICATION_NAME, MavenPublication.class);
        mavenPublication.from(project.getComponents().getByName(SOFTWARE_COMPONENT_NAME));
        mavenPublication.artifact((War)project.getTasks().getByName("war"));
    }

As I was looking at the JavaPlugin I found the configurations that I’ve never used in the dsl: apiElements and runtimeElements. Is there a explanation what they are for and how or better when one must use them?

Actually the JavaPlugin enhances these two configurations with the jarArtifact:

        PublishArtifact jarArtifact = new LazyPublishArtifact(jar);
        ...
        addJar(apiElementConfiguration, jarArtifact);
        addJar(runtimeConfiguration, jarArtifact);
        ...

    private void addJar(Configuration configuration, PublishArtifact jarArtifact) {
        ConfigurationPublications publications = configuration.getOutgoing();

        // Configure an implicit variant
        publications.getArtifacts().add(jarArtifact);
        publications.getAttributes().attribute(ArtifactAttributes.ARTIFACT_FORMAT, ArtifactTypeDefinition.JAR_TYPE);
    }

I was looking for something like that, but as I’am not registering the war task in my plugin I have no Provider<?> and can not initiate a LazyPublishArtifact. So I ended up implementing this:

    public void apply(...) {
        ...
        final ArchivePublishArtifact artifact = new ArchivePublishArtifact((War)project.getTasks().getByName(WarPlugin.WAR_TASK_NAME));
        addWar(providedCompileConfiguration, artifact);
        addWar(providedRuntimeConfiguration, artifact);
        ...
    }

    private void addWar(Configuration configuration, PublishArtifact jarArtifact) {
        ConfigurationPublications publications = configuration.getOutgoing();
        // Configure an implicit variant
        publications.getArtifacts().add(jarArtifact);
        publications.getAttributes().attribute(ArtifactAttributes.ARTIFACT_FORMAT, "war");
    }

To be honest I actually do not understand what the attributes imply, when they are used and why there’s a difference between the api and apiElements configuration or if that is another way to express what was formerly the artifacts configuration.

Also why are variants tied one-to-one with configurations. Adding a new variant when mapping a configuration to a maven scope fells kind of wrong, as in my simple case all configurations may be relevant for the same consumer/variant of my artifact.

I hope you have the time to answer some of the questions and my implementation is actually in line with the intentions of the software component idea - always love to understand a bit more about the gradle concepts to be able to implement better plugins.

kind regards
Daniel

Update:
I found this very interesting documentation: https://docs.gradle.org/6.0-rc-1/userguide/cross_project_publications.html#sec:simple-sharing-artifacts-between-projects
that realy helps to understand the concept much better.

So if I read this correctly the whole variant aware dependency resolution thing is only starting to gain momentum when the consuming Ear attaches attributes to the deploy configuration?
We’ll be able to declare deploy project(':local-war') dependencies when the war plugin provides a software component variant with attributes (lets say category=ear-module) and the same attributes are used on the Ears deploy configuration. This should then also be transfered to ejb jar projects.

That would realy make a interesting use case, but will also require a ejb plugin and changes to the war plugin and the ear plugin.
For the war that might result in a new earProvided configuration that will be used to declare dependencies for a software component variant that is consumed by a ear while a standalone variant must package these dependencyies in the war, right? I currently cannot imagine how that might look like when publishing those variants (or should they be different components?) to a maven repository.


Viewing all articles
Browse latest Browse all 19888

Trending Articles