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 Ear
s 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.