Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Gradle metadata #461

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip
distributionUrl=https://services.gradle.org/distributions-snapshots/gradle-5.3-20190226013556+0000-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
@@ -1,30 +1,59 @@
package com.github.jengelman.gradle.plugins.shadow

import com.github.jengelman.gradle.plugins.shadow.tasks.KnowsTask
import groovy.transform.CompileStatic
import org.gradle.api.GradleException
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.LibraryElements
import org.gradle.api.attributes.Usage
import org.gradle.api.attributes.java.TargetJvmVersion
import org.gradle.util.GradleVersion

class ShadowBasePlugin implements Plugin<Project> {

static final String EXTENSION_NAME = 'shadow'
static final String CONFIGURATION_NAME = 'shadow'
static final String SHADOW_CONFIGURATION_NAME = 'shadow'
static final String SHADOW_OUTGOING_API_CONFIGURATION_NAME = 'shadowApiElements'
static final String SHADOW_OUTGOING_RUNTIME_CONFIGURATION_NAME = 'shadowRuntimeElements'

@Override
void apply(Project project) {
if (GradleVersion.current() < GradleVersion.version("5.0")) {
throw new GradleException("This version of Shadow supports Gradle 5.0+ only. Please upgrade.")
}
project.extensions.create(EXTENSION_NAME, ShadowExtension, project)
createShadowConfiguration(project)
createShadowConfigurations(project)

KnowsTask knows = project.tasks.create(KnowsTask.NAME, KnowsTask)
knows.group = ShadowJavaPlugin.SHADOW_GROUP
knows.description = KnowsTask.DESC
}

private void createShadowConfiguration(Project project) {
project.configurations.create(CONFIGURATION_NAME)
@CompileStatic
private void createShadowConfigurations(Project project) {
project.configurations.with {
def shadowConf = create(SHADOW_CONFIGURATION_NAME)
[(SHADOW_OUTGOING_API_CONFIGURATION_NAME): Usage.JAVA_API,
(SHADOW_OUTGOING_RUNTIME_CONFIGURATION_NAME): Usage.JAVA_RUNTIME
].each { configurationName, usage ->
create(configurationName) { Configuration conf ->
conf.with {
extendsFrom shadowConf
canBeResolved = false
canBeConsumed = true
attributes {
it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage, usage))
it.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements, LibraryElements.JAR))
it.attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling, Bundling.SHADOWED))
it.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, Integer.valueOf(JavaVersion.current().majorVersion))
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,40 @@
package com.github.jengelman.gradle.plugins.shadow

import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import groovy.transform.CompileStatic
import org.gradle.api.Action
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.PublishArtifact
import org.gradle.api.artifacts.maven.Conf2ScopeMappingContainer
import org.gradle.api.artifacts.maven.MavenPom
import org.gradle.api.component.AdhocComponentWithVariants
import org.gradle.api.component.ConfigurationVariantDetails
import org.gradle.api.component.SoftwareComponentFactory
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.plugins.MavenPlugin
import org.gradle.api.tasks.Upload
import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.configuration.project.ProjectConfigurationActionContainer
import org.gradle.util.GradleVersion

import javax.inject.Inject

import static org.gradle.api.plugins.JavaBasePlugin.UNPUBLISHABLE_VARIANT_ARTIFACTS

class ShadowJavaPlugin implements Plugin<Project> {

static final String SHADOW_JAR_TASK_NAME = 'shadowJar'
static final String SHADOW_UPLOAD_TASK = 'uploadShadow'
static final String SHADOW_GROUP = 'Shadow'

private final ProjectConfigurationActionContainer configurationActionContainer;
private final ProjectConfigurationActionContainer configurationActionContainer
private final SoftwareComponentFactory softwareComponentFactory

@Inject
ShadowJavaPlugin(ProjectConfigurationActionContainer configurationActionContainer) {
ShadowJavaPlugin(ProjectConfigurationActionContainer configurationActionContainer, SoftwareComponentFactory factory) {
this.configurationActionContainer = configurationActionContainer
this.softwareComponentFactory = factory
}

@Override
Expand All @@ -51,7 +60,7 @@ class ShadowJavaPlugin implements Plugin<Project> {
}
shadow.manifest.inheritFrom project.tasks.jar.manifest
shadow.doFirst {
def files = project.configurations.findByName(ShadowBasePlugin.CONFIGURATION_NAME).files
def files = project.configurations.findByName(ShadowBasePlugin.SHADOW_CONFIGURATION_NAME).files
if (files) {
def libs = [project.tasks.jar.manifest.attributes.get('Class-Path')]
libs.addAll files.collect { "${it.name}" }
Expand All @@ -63,8 +72,9 @@ class ShadowJavaPlugin implements Plugin<Project> {
project.configurations.runtimeClasspath : project.configurations.runtime]
shadow.exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'module-info.class')

project.artifacts.add(ShadowBasePlugin.CONFIGURATION_NAME, shadow)
project.artifacts.add(ShadowBasePlugin.SHADOW_CONFIGURATION_NAME, shadow)
configureShadowUpload()
configurePublications(project, shadow)
}

private void configureShadowUpload() {
Expand All @@ -84,4 +94,50 @@ class ShadowJavaPlugin implements Plugin<Project> {
}
})
}

@CompileStatic
private void configurePublications(Project project, ShadowJar shadowJar) {
AdhocComponentWithVariants shadowComponent = softwareComponentFactory.adhoc("shadowJava")
shadowComponent.with {
project.components.add(it)
// add the regular variants, with an additional "shadow" attribute
addVariantsFromConfiguration(project.configurations.getByName(JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME), new PublishableVariantSpec("compile", false))
addVariantsFromConfiguration(project.configurations.getByName(JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME), new PublishableVariantSpec("runtime", false))
// now add the shadow specific variants
addVariantsFromConfiguration(project.configurations.getByName(ShadowBasePlugin.SHADOW_OUTGOING_API_CONFIGURATION_NAME), new PublishableVariantSpec("compile", true))
addVariantsFromConfiguration(project.configurations.getByName(ShadowBasePlugin.SHADOW_OUTGOING_RUNTIME_CONFIGURATION_NAME), new PublishableVariantSpec("runtime", true));
}
registerShadowArtifact(project, ShadowBasePlugin.SHADOW_OUTGOING_API_CONFIGURATION_NAME, shadowJar)
registerShadowArtifact(project, ShadowBasePlugin.SHADOW_OUTGOING_RUNTIME_CONFIGURATION_NAME, shadowJar)
}

@CompileStatic
private static void registerShadowArtifact(Project project, String configurationName, ShadowJar shadowJar) {
project.artifacts.add(configurationName, shadowJar)
}

@CompileStatic
private static class PublishableVariantSpec implements Action<ConfigurationVariantDetails> {
private final String scope
private final boolean optional
PublishableVariantSpec(String scope, boolean optional) {
this.scope = scope
this.optional = optional
}

@Override
void execute(ConfigurationVariantDetails details) {
def variant = details.configurationVariant
for (PublishArtifact artifact : variant.artifacts) {
if (UNPUBLISHABLE_VARIANT_ARTIFACTS.contains(artifact.type)) {
details.skip()
return
}
}
details.mapToMavenScope(scope)
if (optional) {
details.mapToOptional()
}
}
}
}
2 changes: 1 addition & 1 deletion src/main/resources/shadow-version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5.1.0
5.1.0-SNAPSHOT
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package com.github.jengelman.gradle.plugins.shadow

import com.github.jengelman.gradle.plugins.shadow.util.AppendableMavenFileRepository
import com.github.jengelman.gradle.plugins.shadow.util.PluginSpecification
import groovy.json.JsonSlurper
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.Usage
import spock.lang.Issue

class PublishingSpec extends PluginSpecification {
Expand Down Expand Up @@ -164,4 +167,110 @@ class PublishingSpec extends PluginSpecification {
assert dependency.artifactId.text() == 'b'
assert dependency.version.text() == '1.0'
}

def "publish shadow jar with maven-publish plugin and Gradle metadata"() {
given:
repo.module('shadow', 'a', '1.0')
.insertFile('a.properties', 'a')
.insertFile('a2.properties', 'a2')
.publish()
repo.module('shadow', 'b', '1.0')
.insertFile('b.properties', 'b')
.publish()

settingsFile << """
rootProject.name = 'maven'
enableFeaturePreview("GRADLE_METADATA")
"""
buildFile << """
apply plugin: 'maven-publish'

dependencies {
compile 'shadow:a:1.0'
compile 'shadow:b:1.0'
shadow 'shadow:b:1.0'
}

group = 'com.acme'
version = '1.0'

publishing {
publications {
java(MavenPublication) {
from components.shadowJava
}
}
repositories {
maven {
url "${publishingRepo.uri}"
}
}
}
""".stripIndent()

when:
runner.withArguments('publish').build()

then:
File mainJar = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.jar').canonicalFile
File shadowJar = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0-all.jar').canonicalFile
assert mainJar.exists()
assert shadowJar.exists()

and:
contains(shadowJar, ['a.properties', 'a2.properties'])

and: "publishes both a POM file and a Gradle metadata file"
File pom = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.pom').canonicalFile
File gmm = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.module').canonicalFile
pom.exists()
gmm.exists()

when: "POM file corresponds to a regular Java publication"
def pomContents = new XmlSlurper().parse(pom)
pomContents.dependencies.size() == 2

then:
def dependency1 = pomContents.dependencies[0].dependency[0]
dependency1.groupId.text() == 'shadow'
dependency1.artifactId.text() == 'a'
dependency1.version.text() == '1.0'

def dependency2 = pomContents.dependencies[0].dependency[1]
dependency2.groupId.text() == 'shadow'
dependency2.artifactId.text() == 'b'
dependency2.version.text() == '1.0'

when: "Gradle module metadata contains the Shadow variants"
def gmmContents = new JsonSlurper().parse(gmm)

then:
gmmContents.variants.size() == 4
gmmContents.variants.name as Set == ['apiElements', 'runtimeElements', 'shadowApiElements', 'shadowRuntimeElements'] as Set

def apiVariant = gmmContents.variants.find { it.name == 'apiElements' }
apiVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_API_JARS
apiVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.EXTERNAL
apiVariant.dependencies.size() == 2
apiVariant.dependencies.module as Set == ['a', 'b'] as Set

def runtimeVariant = gmmContents.variants.find { it.name == 'runtimeElements' }
runtimeVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_RUNTIME_JARS
runtimeVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.EXTERNAL
runtimeVariant.dependencies.size() == 2
apiVariant.dependencies.module as Set == ['a', 'b'] as Set

def shadowApiVariant = gmmContents.variants.find { it.name == 'shadowApiElements' }
shadowApiVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_API_JARS
shadowApiVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.SHADOWED
shadowApiVariant.dependencies.size() == 1
shadowApiVariant.dependencies.module as Set == ['b'] as Set

def shadowRuntimeVariant = gmmContents.variants.find { it.name == 'shadowRuntimeElements' }
shadowRuntimeVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_RUNTIME_JARS
shadowRuntimeVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.SHADOWED
shadowRuntimeVariant.dependencies.size() == 1
shadowRuntimeVariant.dependencies.module as Set == ['b'] as Set

}
}