Skip to content
This repository has been archived by the owner on Jan 15, 2024. It is now read-only.

Commit

Permalink
Perform version checking and version mapping against separate configs
Browse files Browse the repository at this point in the history
Previously the springioTestRuntime configuration was used both when
checking that all of a project's dependencies were part of the
platform and when modifying those dependencies to use the platform's
versions. This meant that test-only dependencies had to be included
in the Platform.

This commit updates the plugin to use separate configuration for
checking that a dependency is in the platform. By default the checking
will be performed against the runtime configuration that's provided by
the Java plugin. The task can be configured to use a different
configuration:

springioDependencyVersionMappingCheck {
	configuration = configurations.configurationToCheck
}

The configuration options for controlling whether or not unmapped
direct dependencies and unmapped transitive dependencies should cause
a failure have been moved from the Spring IO platform extension onto
this task. These options can be configured as follows:

springioDependencyVersionMappingCheck {
	failOnUnmappedDirectDependency = true
	failOnUnmappedTransitiveDependency = true
}

The Spring IO platform extension has been removed.
  • Loading branch information
wilkinsona committed May 1, 2014
1 parent aeefc3d commit 5523434
Show file tree
Hide file tree
Showing 14 changed files with 447 additions and 423 deletions.
73 changes: 42 additions & 31 deletions springio-platform-plugin/README.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Rob Winch
:doctype: book

== Overview
Provides additional checks to ensure springio platform compatibility
Provides additional checks to ensure Spring IO platform compatibility

== Quick Start

Expand Down Expand Up @@ -48,17 +48,17 @@ Now you can run the following:

[source,bash]
----
$ ./gradlew clean springioCheck -PJDK8_HOME=<jdk8-home> -PJDK7_HOME=<jdk7-home>
$ ./gradlew clean springioCheck
----

This will:
This will execute tasks that:

* Check that Spring IO contains versions for all direct dependencies, all transitive dependencies, or both. For more
information refer to <<spring-io-dependencies>>
information refer to the <<springiodependencyversionmappingcheck, description of the task>>
* Ensure that all dependency exclusions use both the group and the module. For more information refer to
<<incompleteexcludestask>>
* Verify that certain dependencies are not used and suggest alternatives. For more information refer to
<<alternativedependenciestask>>
the <<springioincompleteexcludescheck, description of the task>>
* Verify that certain dependencies are not used and suggest alternatives if they are. For more information
refer to the <<springioalternativedependenciescheck, description of the task>>

Alternatively, you can run the following:

Expand All @@ -67,10 +67,10 @@ Alternatively, you can run the following:
$ ./gradlew clean springioCheck -PJDK8_HOME=<jdk8-home> -PJDK7_HOME=<jdk7-home>
----

In addition to the steps listed above this will also:
In addition to the steps listed above this will execute tasks that:

* Assist with running tests against your compiled code using JDK7 and JDK8 and the Spring IO dependency versions. For
more information refer to <<additional-tests>>
* Running tests against your compiled code using JDK7 and JDK8 and the Spring IO dependency versions. For more
information refer to <<additional-tests, Additional Tests>>

If you would like springioCheck to be invoked when you run `./gradlew build`, then you can make the check task depend
on springioCheck as shown below:
Expand All @@ -92,19 +92,7 @@ Typically users will keep the springioCheck task separate so as to only run the

The plugin creates a new configuration, `springioTestRuntime`, that contains all of the project's dependencies with
their versions mapped to those that are in the platform. This configuration is used when running the additional
tests. By default, if a direct dependency is encountered that is not part of the platform the build will fail. This
can be configured using the `springIoPlatform` extension. For example:

[source,groovy]
springioPlatform {
failOnUnmappedDirectDependency = true
failOnUnmappedTransitiveDependency = true
}

`failOnUnmappedDirectDependency` controls whether or not the build will fail if a direct dependency is encountered that
is not part of the Spring IO plaform. The default is `true`. `failOnUnmappedTransitiveDependency` controls whether or
not the build will fail if a transitive dependency is encountered that is not part of the Spring IO platform. The
default is `false`.
tests.

You can use Gradle's built-in `dependencies` task to see details of the `springioTestRuntime` configuration and the
versions that it contains. For example:
Expand Down Expand Up @@ -143,7 +131,11 @@ example above works with the Spring Bamboo environment.

NOTE: You can also place JDK8_HOME and JDK7_HOME in your gradle.properties

== IncompleteExcludesTask
== Sub-tasks

The plugin adds a number of tasks to your build. These are documented below.

=== springioIncompleteExcludesCheck

This task ensures that any dependency exclusions that are done use both the group and the module because otherwise the
dependency will not be excluded in the generated pom.xml file. For example the following is not allowed because it only
Expand All @@ -152,9 +144,9 @@ excludes the module:
[source,groovy]
----
dependencies {
compile('org.springframework:spring-core:3.2.0.RELEASE') {
exclude module: 'commons-logging'
}
compile('org.springframework:spring-core:3.2.0.RELEASE') {
exclude module: 'commons-logging'
}
}
----

Expand All @@ -163,9 +155,9 @@ the following is not allowed because it only excludes the group:
[source,groovy]
----
dependencies {
compile('org.springframework:spring-core:3.2.0.RELEASE') {
exclude group: 'commons-logging'
}
compile('org.springframework:spring-core:3.2.0.RELEASE') {
exclude group: 'commons-logging'
}
}
----

Expand All @@ -180,7 +172,26 @@ dependencies {
}
----

== AlternativeDependenciesTask
=== springioAlternativeDependenciesCheck

This task will ensure certain dependencies are not used and suggest alternatives. For example, intead of using asm:asm
it is preferred to use spring-core's repackages asm dependencies.

=== springioDependencyVersionMappingCheck

This task will check that every dependency in a configuration can be mapped to a dependency that's part of the
Spring IO Platform. By default, the task will perform this check against the `runtime` configuration. The build will
fail if unmapped direct dependencies are found, but unmapped transitive dependencies will not cause a failure. All
three options can be configured:

[source,groovy]
springioDependencyVersionMappingCheck {
configuration = configurations.testRuntime
failOnUnmappedDirectDependency = true
failOnUnmappedTransitiveDependency = true
}

`configuration` determines the configuration that is checked. `failOnUnmappedDirectDependency` controls whether or not
the build will fail if a direct dependency is encountered that is not part of the Spring IO plaform. The default is
`true`. `failOnUnmappedTransitiveDependency` controls whether or not the build will fail if a transitive dependency is
encountered that is not part of the Spring IO platform. The default is `false`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import java.util.Map;
import java.util.Set;

import org.gradle.api.Action;
import org.gradle.api.artifacts.DependencyResolveDetails;
import org.gradle.api.artifacts.ModuleVersionSelector;

abstract class AbstractDependencyResolveDetailsAction implements Action<DependencyResolveDetails> {

Map<String,ModuleVersionSelector> dependencyToSelector = [:]

/**
* In the form {@code group:name}
*/
Set<String> ignoredDependencies = []

void execute(DependencyResolveDetails details) {
if (!isIgnoredDependency(details)) {
ModuleVersionSelector selector = getSelector(details)
execute(details, selector)
}
}

protected abstract void execute(DependencyResolveDetails details, ModuleVersionSelector springIoMapping)

private boolean isIgnoredDependency(DependencyResolveDetails details) {
ignoredDependencies.contains(getId(details))
}

protected ModuleVersionSelector getSelector(DependencyResolveDetails details) {
dependencyToSelector[getId(details)]
}

private String getId(DependencyResolveDetails details) {
"$details.requested.group:$details.requested.name"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.springframework.build.gradle.springio.platform;

import org.gradle.api.Action
import org.gradle.api.InvalidUserDataException
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.DependencyResolveDetails
import org.gradle.api.artifacts.ModuleVersionSelector
import org.gradle.api.artifacts.ResolvableDependencies
import org.gradle.api.internal.artifacts.DefaultModuleVersionSelector

/**
* @author Rob Winch
* @author Andy Wilkinson
*/
abstract class AbstractPlatformDependenciesBeforeResolveAction implements Action<ResolvableDependencies> {

Project project

Configuration configuration

String resource = 'springio-dependencies'

@Override
public void execute(ResolvableDependencies resolvableDependencies) {
Map<String, ModuleVersionSelector> selectors = createSelectorsFromStream(getClass().getResourceAsStream(resource))
doExecute(resolvableDependencies, selectors)
}

abstract void doExecute(ResolvableDependencies resolvableDependencies, Map<String, ModuleVersionSelector> selectors)

/**
* Reads the given stream, each line of which is expected to be in the format {@code group:artifact:version}, and
* returns a {@code Map<String, ModuleVersionSelector>} where the keys are of the form {@code group:version} and
* the values are ModuleVersion selectors created with {@code group}, {@code name}, and {@code version}.
*
* @param stream The stream to read the dependency information from
*
* @return The map of selectors
*/
private Map<String, ModuleVersionSelector> createSelectorsFromStream(InputStream stream) {
Map<String,ModuleVersionSelector> depToSelector = [:]
stream.eachLine { line ->
if(line && !line.startsWith('#')) {
def (group, name, version) = line.split(':')
depToSelector.put("$group:$name" as String, new DefaultModuleVersionSelector(group, name, version))
}
}
depToSelector
}

protected Set<String> getIgnoredDependencies() {
project.rootProject.allprojects.collect { "$it.group:$it.name" as String }
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.springframework.build.gradle.springio.platform

import org.gradle.api.InvalidUserDataException
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.DependencyResolveDetails
import org.gradle.api.artifacts.ModuleVersionSelector
import org.gradle.api.artifacts.ResolvableDependencies

class CheckPlatformDependenciesBeforeResolveAction extends AbstractPlatformDependenciesBeforeResolveAction {

boolean failOnUnmappedDirectDependency = true

boolean failOnUnmappedTransitiveDependency = false

@Override
public void doExecute(ResolvableDependencies resolvableDependencies, Map<String, ModuleVersionSelector> selectors) {
CheckingDependencyResolveDetailsAction checkingAction = new CheckingDependencyResolveDetailsAction(
dependencyToSelector: selectors, configuration: configuration, ignoredDependencies: ignoredDependencies)

configuration.resolutionStrategy.eachDependency checkingAction
configuration.incoming.afterResolve {
String message
if (failOnUnmappedDirectDependency && checkingAction.unmappedDirectDependencies) {
message = "The following direct dependencies do not have Spring IO versions: " + checkingAction.unmappedDirectDependencies.collect { "$it.group:$it.name" }.join(", ")
}

if (failOnUnmappedTransitiveDependency && checkingAction.unmappedTransitiveDependencies) {
message = message ? message + ". " : ""
message += "The following transitive dependencies do not have Spring IO versions: " + checkingAction.unmappedTransitiveDependencies.collect { "$it.group:$it.name" }.join(", ")
}

if (message) {
throw new InvalidUserDataException(message)
}
}
}

private static class CheckingDependencyResolveDetailsAction extends AbstractDependencyResolveDetailsAction {

Configuration configuration

List<ModuleVersionSelector> unmappedDirectDependencies = []

List<ModuleVersionSelector> unmappedTransitiveDependencies = []

void execute(DependencyResolveDetails details, ModuleVersionSelector springIoMapping) {
ModuleVersionSelector requested = details.requested
if(!springIoMapping) {
if (isDirectDependency(requested)) {
unmappedDirectDependencies << requested
} else {
unmappedTransitiveDependencies << requested
}
} else {
details.useTarget springIoMapping
}
}

private boolean isDirectDependency(ModuleVersionSelector selector) {
for (Dependency dependency: configuration.allDependencies) {
if (dependency.group == selector.group && dependency.name == selector.name) {
return true
}
}
return false
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.springframework.build.gradle.springio.platform

import org.gradle.api.DefaultTask
import org.gradle.api.artifacts.Configuration
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction

class DependencyVersionMappingCheckTask extends DefaultTask {

@Input
@Optional
Configuration configuration

@Input
@Optional
boolean failOnUnmappedDirectDependency = true

@Input
@Optional
boolean failOnUnmappedTransitiveDependency = false

@TaskAction
void checkVersionMapping() {
if (!configuration) {
configuration = project.configurations.getByName(JavaPlugin.RUNTIME_CONFIGURATION_NAME)
}

configuration.incoming.beforeResolve(
new CheckPlatformDependenciesBeforeResolveAction(project: project, configuration: configuration,
failOnUnmappedDirectDependency: failOnUnmappedDirectDependency,
failOnUnmappedTransitiveDependency: failOnUnmappedTransitiveDependency))

configuration.resolvedConfiguration
}

void setConfiguration(Configuration configuration) {
this.configuration = configuration;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.springframework.build.gradle.springio.platform

import org.gradle.api.artifacts.DependencyResolveDetails;
import org.gradle.api.artifacts.ModuleVersionSelector;
import org.gradle.api.artifacts.ResolvableDependencies;

class MapPlatformDependenciesBeforeResolveAction extends AbstractPlatformDependenciesBeforeResolveAction {

@Override
public void doExecute(ResolvableDependencies resolvableDependencies, Map<String, ModuleVersionSelector> selectors) {
MappingDependencyResolveDetailsAction action = new MappingDependencyResolveDetailsAction(
dependencyToSelector: selectors, ignoredDependencies: ignoredDependencies)
configuration.resolutionStrategy.eachDependency action
}

private static class MappingDependencyResolveDetailsAction extends AbstractDependencyResolveDetailsAction {
void execute(DependencyResolveDetails details, ModuleVersionSelector springIoMapping) {
if(springIoMapping) {
details.useTarget springIoMapping
}
}
}
}
Loading

0 comments on commit 5523434

Please sign in to comment.