Skip to content
Merged
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
4 changes: 2 additions & 2 deletions src/docs/publishing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ apply plugin: 'com.gradleup.shadow'

publishing {
publications {
shadow(MavenPublication) { publication ->
project.shadow.component(publication)
shadow(MavenPublication) {
components.shadow
}
}
repositories {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,74 +1,23 @@
package com.github.jengelman.gradle.plugins.shadow

import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.Project
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.SelfResolvingDependency
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.publish.maven.MavenPom
import org.gradle.api.component.SoftwareComponentContainer
import org.gradle.api.publish.maven.MavenPublication

@Deprecated
class ShadowExtension {
private final Provider<Archive> archive
private final Provider<List<Dep>> allDependencies
private final SoftwareComponentContainer components

ShadowExtension(Project project) {
archive = project.provider {
def archiveTask = project.tasks.withType(ShadowJar).getByName("shadowJar")
new Archive(archiveTask.archiveFile, archiveTask.archiveClassifier)
}
allDependencies = project.provider {
project.configurations.getByName("shadow").allDependencies.collect {
if ((it instanceof ProjectDependency) || !(it instanceof SelfResolvingDependency)) {
new Dep(it.group, it.name, it.version)
}
}
}
components = project.components
}

/**
* @param publication
* @deprecated configure publication using component.shadow directly
*/
@Deprecated
void component(MavenPublication publication) {
publication.artifact([
source : archive.get().file,
classifier: archive.get().classifier.get()
])

// Don't inline this variable, it seems Groovy closure capturing is confused by the field instead of a local variable.
final def allDeps = allDependencies
publication.pom { MavenPom pom ->
pom.withXml { xml ->
def dependenciesNode = xml.asNode().get('dependencies') ?: xml.asNode().appendNode('dependencies')
allDeps.get().each {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
dependencyNode.appendNode('scope', 'runtime')
}
}
}
}

private class Archive {
Provider<RegularFile> file
Property<String> classifier

Archive(Provider<RegularFile> file, Property<String> classifier) {
this.file = file
this.classifier = classifier
}
}

private class Dep {
String group
String name
String version

Dep(String group, String name, String version) {
this.group = group
this.name = name
this.version = version
}
publication.from(components.findByName("shadow"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import org.gradle.api.attributes.Category
import org.gradle.api.attributes.LibraryElements
import org.gradle.api.attributes.Usage
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.component.AdhocComponentWithVariants
import org.gradle.api.component.SoftwareComponentFactory
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.configuration.project.ProjectConfigurationActionContainer
import org.gradle.plugin.devel.plugins.JavaGradlePluginPlugin

import javax.inject.Inject
Expand All @@ -19,39 +20,41 @@ class ShadowJavaPlugin implements Plugin<Project> {
public static final String SHADOW_JAR_TASK_NAME = 'shadowJar'
public static final String SHADOW_GROUP = 'Shadow'

private final ProjectConfigurationActionContainer configurationActionContainer
private final SoftwareComponentFactory softwareComponentFactory

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

@Override
void apply(Project project) {
configureShadowTask(project)
def shadowTask = configureShadowTask(project)

project.configurations.compileClasspath.extendsFrom project.configurations.shadow

project.configurations {
shadowRuntimeElements {
canBeConsumed = true
canBeResolved = false
attributes {
it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage, Usage.JAVA_RUNTIME))
it.attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category, Category.LIBRARY))
it.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements, LibraryElements.JAR))
it.attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling, Bundling.SHADOWED))
}
outgoing.artifact(project.tasks.named(SHADOW_JAR_TASK_NAME))
project.configurations.register("shadowRuntimeElements") {
it.extendsFrom(project.configurations.shadow)
it.canBeConsumed = true
it.canBeResolved = false
it.attributes {
it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage, Usage.JAVA_RUNTIME))
it.attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category, Category.LIBRARY))
it.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements, LibraryElements.JAR))
it.attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling, Bundling.SHADOWED))
}
it.outgoing.artifact(shadowTask)
}

project.configurations.shadowRuntimeElements.extendsFrom project.configurations.shadow
AdhocComponentWithVariants javaComponent = (AdhocComponentWithVariants) project.components.findByName("java")
javaComponent.addVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
it.mapToOptional()
}

project.components.java {
addVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
mapToOptional() // make it a Maven optional dependency
}
AdhocComponentWithVariants shadow = softwareComponentFactory.adhoc("shadow")
project.components.add(shadow)
shadow.addVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
it.mapToMavenScope("runtime")
}

project.plugins.withType(JavaGradlePluginPlugin).configureEach {
Expand All @@ -68,9 +71,9 @@ class ShadowJavaPlugin implements Plugin<Project> {
}
}

protected static void configureShadowTask(Project project) {
protected static ShadowJar configureShadowTask(Project project) {
SourceSetContainer sourceSets = project.extensions.getByType(SourceSetContainer)
project.tasks.register(SHADOW_JAR_TASK_NAME, ShadowJar) { shadow ->
def taskProvider = project.tasks.register(SHADOW_JAR_TASK_NAME, ShadowJar) { shadow ->
shadow.group = SHADOW_GROUP
shadow.description = 'Create a combined JAR of project and runtime dependencies'
shadow.archiveClassifier.set("all")
Expand All @@ -91,6 +94,7 @@ 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, project.tasks.named(SHADOW_JAR_TASK_NAME))
project.artifacts.add(ShadowBasePlugin.CONFIGURATION_NAME, taskProvider.get())
return taskProvider.get()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ class PublishingSpec extends PluginSpecification {

publishing {
publications {
shadow(MavenPublication) { publication ->
project.shadow.component(publication)
shadow(MavenPublication) {
from components.shadow
artifactId = 'maven-all'
}
}
Expand Down Expand Up @@ -191,8 +191,8 @@ class PublishingSpec extends PluginSpecification {

publishing {
publications {
shadow(MavenPublication) { publication ->
project.shadow.component(publication)
shadow(MavenPublication) {
from components.shadow
artifactId = 'maven-all'
}
}
Expand Down Expand Up @@ -250,6 +250,10 @@ class PublishingSpec extends PluginSpecification {
java(MavenPublication) {
from components.java
}
shadow(MavenPublication) {
from components.shadow
artifactId = "maven-all"
}
}
repositories {
maven {
Expand All @@ -262,59 +266,90 @@ class PublishingSpec extends PluginSpecification {
when:
run('publish')

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() == 3
gmmContents.variants.name as Set == ['apiElements', 'runtimeElements', 'shadowRuntimeElements'] as Set

def apiVariant = gmmContents.variants.find { it.name == 'apiElements' }
apiVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_API
apiVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.EXTERNAL
!apiVariant.dependencies

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

def shadowRuntimeVariant = gmmContents.variants.find { it.name == 'shadowRuntimeElements' }
shadowRuntimeVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_RUNTIME
shadowRuntimeVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.SHADOWED
shadowRuntimeVariant.dependencies.size() == 1
shadowRuntimeVariant.dependencies.module as Set == ['b'] as Set
then: "verify java publication with shadow variant"
assertions {
File jar = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.jar').canonicalFile
assert jar.exists()
}
assertions {
File jar = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0-all.jar').canonicalFile
assert jar.exists()
contains(jar, ['a.properties', 'a2.properties'])
}
assertions {
File pom = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.pom').canonicalFile
assert pom.exists()
def pomContents = new XmlSlurper().parse(pom)
assert pomContents.dependencies[0].dependency.size() == 2

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

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

assertions {
File gmm = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.module').canonicalFile
assert gmm.exists()
def gmmContents = new JsonSlurper().parse(gmm)
assert gmmContents.variants.size() == 3
assert gmmContents.variants.name as Set == ['apiElements', 'runtimeElements', 'shadowRuntimeElements'] as Set

def apiVariant = gmmContents.variants.find { it.name == 'apiElements' }
assert apiVariant.attributes[Usage.USAGE_ATTRIBUTE.name] == Usage.JAVA_API
assert apiVariant.attributes[Bundling.BUNDLING_ATTRIBUTE.name] == Bundling.EXTERNAL
assert !apiVariant.dependencies

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

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

and: "verify shadow publication"
assertions {
File jar = publishingRepo.rootDir.file('com/acme/maven-all/1.0/maven-all-1.0-all.jar').canonicalFile
assert jar.exists()
contains(jar, ['a.properties', 'a2.properties'])
}

assertions {
File pom = publishingRepo.rootDir.file('com/acme/maven-all/1.0/maven-all-1.0.pom').canonicalFile
assert pom.exists()
def pomContents = new XmlSlurper().parse(pom)
assert pomContents.dependencies[0].dependency.size() == 1

def dependency1 = pomContents.dependencies[0].dependency[0]
assert dependency1.groupId.text() == 'shadow'
assert dependency1.artifactId.text() == 'b'
assert dependency1.version.text() == '1.0'
}

assertions {
File gmm = publishingRepo.rootDir.file('com/acme/maven-all/1.0/maven-all-1.0.module').canonicalFile
assert gmm.exists()
def gmmContents = new JsonSlurper().parse(gmm)
assert gmmContents.variants.size() == 1
assert gmmContents.variants.name as Set == ['shadowRuntimeElements'] as Set

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

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@ abstract class PluginSpecification extends Specification {
jar.close()
}

// Helper method to allow scoping variables into a closure in a spock test
// Prevents variable expansion
// When using this you *must* include explicit `assert` statements as Spock will not do it for you
void assertions(Closure closure) {
closure()
}

AppendableJar buildJar(String path) {
return new AppendableJar(file(path))
}
Expand Down