Skip to content

Commit

Permalink
Merge pull request #14 from rspieldenner/changeresolve
Browse files Browse the repository at this point in the history
bugfixes related to use with dependencyLock and other modifications t…
  • Loading branch information
rspieldenner committed Apr 19, 2016
2 parents 98053f6 + 0c02c9e commit a76cbcc
Show file tree
Hide file tree
Showing 8 changed files with 304 additions and 63 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,8 @@
1.2.1 / 2016/04/19
==================
- BUGFIX: Make sure resolutionRules configuration can be locked by nebula.dependency-lock
- BUGFIX: Allow other changes to configurations.all and associated resolutionStrategy

1.2.0 / 2016/04/11
==================
- Allow opt out of rules for shared company wide rules that apply to your project, e.g. there is a common align rule for a:foo and a:bar and you produce them
Expand Down
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -21,7 +21,7 @@ The [Blacklist Plugin](https://github.com/nebula-plugins/gradle-blacklist-plugin
}
dependencies {
classpath 'com.netflix.nebula:gradle-resolution-rules-plugin:1.2.0'
classpath 'com.netflix.nebula:gradle-resolution-rules-plugin:1.2.1'
}
}
Expand All @@ -32,7 +32,7 @@ Or using the Gradle plugin portal:

```groovy
plugins {
id 'nebula.resolution-rules' version '1.2.0'
id 'nebula.resolution-rules' version '1.2.1'
}
```

Expand Down
5 changes: 5 additions & 0 deletions build.gradle
Expand Up @@ -57,6 +57,11 @@ facets {
}
}

tasks.withType(Test) {
maxHeapSize = '512m'
jvmArgs '-XX:MaxPermSize=128m'
}

apply from: 'gradle/idea.gradle'
apply from: 'https://raw.githubusercontent.com/nebula-plugins/nebula-core/59c9e15f561372a8a72bbe13e4fbb114d0ef16f8/common.gradle'

Expand Down
Expand Up @@ -14,13 +14,17 @@
* limitations under the License.
*
*/

package nebula.plugin.resolutionrules

import nebula.test.IntegrationSpec
import nebula.test.dependencies.DependencyGraphBuilder
import nebula.test.dependencies.GradleDependencyGenerator

import java.util.jar.Attributes
import java.util.jar.JarEntry
import java.util.jar.JarOutputStream
import java.util.jar.Manifest

class AlignRulesPluginInteractionSpec extends IntegrationSpec {
def 'alignment interaction with dependency-recommender'() {
def graph = new DependencyGraphBuilder()
Expand Down Expand Up @@ -301,7 +305,6 @@ class AlignRulesPluginInteractionSpec extends IntegrationSpec {
result.standardOutput.contains '\\--- test.a:b: -> 1.2.1\n'
}

@spock.lang.Ignore
def 'cycle like behavior'() {
def graph = new DependencyGraphBuilder()
.addModule('test.nebula:c:1.42.2')
Expand All @@ -322,11 +325,13 @@ class AlignRulesPluginInteractionSpec extends IntegrationSpec {

buildFile << """\
buildscript {
repositories { jcenter() }
repositories {
jcenter()
}
dependencies {
classpath 'com.netflix.nebula:nebula-publishing-plugin:4.4.4'
classpath 'com.netflix.nebula:gradle-extra-configurations-plugin:3.0.3'
classpath 'com.netflix.nebula:gradle-extra-configurations-plugin:3.1.0'
}
}
subprojects {
Expand Down Expand Up @@ -366,4 +371,142 @@ class AlignRulesPluginInteractionSpec extends IntegrationSpec {
then:
noExceptionThrown()
}

def 'able to lock rules'() {
def graph = new DependencyGraphBuilder()
.addModule('test.nebula:a:1.41.5')
.addModule('test.nebula:a:1.42.2')
.addModule('test.nebula:b:1.41.5')
.addModule('test.nebula:b:1.42.2')
.build()
def mavenrepo = new GradleDependencyGenerator(graph, "$projectDir/testrepogen")
mavenrepo.generateTestMavenRepo()

def rulesFolder = new File(projectDir, 'rules')
rulesFolder.mkdirs()
def rulesJsonFile = new File(rulesFolder, 'rules.json')

rulesJsonFile << '''\
{
"deny": [], "reject": [], "substitute": [], "replace": [],
"align": [
{
"name": "testNebula",
"group": "test.nebula",
"reason": "Align test.nebula dependencies",
"author": "Example Person <person@example.org>",
"date": "2016-03-17T20:21:20.368Z"
}
]
}
'''.stripIndent()

def mavenForRules = new File(projectDir, 'repo')
mavenForRules.mkdirs()
def locked = new File(mavenForRules, 'test/rules/resolution-rules/1.0.0')
locked.mkdirs()
createRulesJar([rulesFolder], projectDir, new File(locked, 'resolution-rules-1.0.0.jar'))
createPom('test.rules', 'resolution-rules', '1.0.0', locked)

rulesJsonFile.text = '''\
{
"deny": [], "reject": [], "substitute": [], "replace": [], "align": []
}
'''.stripIndent()
def newer = new File(mavenForRules, 'test/rules/resolution-rules/1.1.0')
newer.mkdirs()
createRulesJar([rulesFolder], projectDir, new File(newer, 'resolution-rules-1.1.0.jar'))
createPom('test.rules', 'resolution-rules', '1.1.0', newer)

def dependencyLock = new File(projectDir, 'dependencies.lock')

dependencyLock << '''\
{
"resolutionRules": {
"test.rules:resolution-rules": { "locked": "1.0.0" }
}
}
'''.stripIndent()

buildFile << """\
buildscript {
repositories { jcenter() }
dependencies {
classpath 'com.netflix.nebula:gradle-dependency-lock-plugin:4.2.0'
}
}
${applyPlugin(ResolutionRulesPlugin)}
apply plugin: 'nebula.dependency-lock'
apply plugin: 'java'
repositories {
${mavenrepo.mavenRepositoryBlock}
maven { url '${mavenForRules.absolutePath}' }
}
dependencies {
resolutionRules 'test.rules:resolution-rules:1.+'
compile 'test.nebula:a:1.41.5'
compile 'test.nebula:b:1.42.2'
}
""".stripIndent()

when:
def results = runTasksSuccessfully('dependencies', '--configuration', 'resolutionRules')

then:
results.standardOutput.contains '\\--- test.rules:resolution-rules:1.+ -> 1.0.0\n'

when:
results = runTasksSuccessfully('dependencies', '--configuration', 'compile')

then:
results.standardOutput.contains '+--- test.nebula:a:1.41.5 -> 1.42.2\n'
results.standardOutput.contains '\\--- test.nebula:b:1.42.2\n'
}

private createRulesJar(Collection<File> files, File unneededRoot, File destination) {
Manifest manifest = new Manifest()
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, '1.0')
JarOutputStream target = new JarOutputStream(new FileOutputStream(destination), manifest)
files.each { add(it, unneededRoot, target) }
target.close()
}

private createPom(String group, String name, String version, File dir) {
def pom = new File(dir, "${name}-${version}.pom")
pom.text = """\
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>${group}</groupId>
<artifactId>${name}</artifactId>
<version>${version}</version>
</project>
""".stripIndent()
}

private void add(File source, File unneededRoot, JarOutputStream target) throws IOException
{
def prefix = "${unneededRoot.path}/"
if (source.isDirectory()) {
String dirName = source.path - prefix
if (!dirName.endsWith('/')) {
dirName += '/'
}
def entry = new JarEntry(dirName)
target.putNextEntry(entry)
target.closeEntry()
source.listFiles().each { nested ->
add(nested, unneededRoot, target)
}
} else {
def entry = new JarEntry(source.path - prefix)
target.putNextEntry(entry)
target << source.bytes
target.closeEntry()
}
}
}
Expand Up @@ -710,4 +710,69 @@ class AlignRulesSpec extends IntegrationSpec {
result.standardOutput.contains '+--- test.nebula:a:1.0.0\n'
result.standardOutput.contains '\\--- test.nebula:b:0.15.0\n'
}

def 'can add additional resolution rules outside of plugin'() {
def graph = new DependencyGraphBuilder()
.addModule('test.nebula:a:1.0.0')
.addModule('test.nebula:a:0.15.0')
.addModule('test.nebula:b:1.0.0')
.addModule('test.nebula:b:0.15.0')
.addModule('test.example:c:0.1.0')
.addModule('test.example:c:0.2.0')
.addModule('test:x:1.0.0')
.addModule('test:x:1.0.1')
.addModule('test:y:1.0.0')
.addModule('test:y:1.0.1')
.build()
File mavenrepo = new GradleDependencyGenerator(graph, "${projectDir}/testrepogen").generateTestMavenRepo()

rulesJsonFile << '''\
{
"deny": [], "reject": [], "substitute": [], "replace": [],
"align": [
{
"name": "testNebula",
"group": "test.nebula",
"reason": "Align test.nebula dependencies",
"author": "Example Person <person@example.org>",
"date": "2016-03-17T20:21:20.368Z"
}
]
}
'''.stripIndent()

buildFile << """\
repositories {
maven { url '${mavenrepo.absolutePath}' }
}
configurations.all {
resolutionStrategy {
force 'test.example:c:0.1.0'
eachDependency { details ->
if (details.requested.group == 'test') {
details.useTarget group: details.requested.group, name: details.requested.name, version: '1.0.0'
}
}
}
}
dependencies {
compile 'test.nebula:a:1.0.0'
compile 'test.nebula:b:0.15.0'
compile 'test.example:c:latest.release'
compile 'test:x:1.+'
compile 'test:y:1.+'
}
""".stripIndent()

when:
def result = runTasksSuccessfully('dependencies', '--configuration', 'compile')

then:
result.standardOutput.contains '+--- test.nebula:a:1.0.0\n'
result.standardOutput.contains '+--- test.nebula:b:0.15.0 -> 1.0.0\n'
result.standardOutput.contains '+--- test.example:c:latest.release -> 0.1.0\n'
result.standardOutput.contains '+--- test:x:1.+ -> 1.0.0\n'
result.standardOutput.contains '\\--- test:y:1.+ -> 1.0.0\n'

}
}
Expand Up @@ -118,9 +118,9 @@ class PluginFunctionalTest extends IntegrationSpec {

def 'warning logged when configuration has been resolved'() {
given:
buildFile << """
configurations.compile.resolvedConfiguration
""".stripIndent()
buildFile << """\
configurations.compile.resolve()
""".stripIndent()

when:
def result = runTasksSuccessfully()
Expand Down
Expand Up @@ -20,28 +20,61 @@ import groovy.json.JsonSlurper
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ResolutionStrategy
import org.slf4j.Logger
import org.slf4j.LoggerFactory

import java.util.zip.ZipEntry
import java.util.zip.ZipFile

class ResolutionRulesPlugin implements Plugin<Project> {
Project project
Logger logger = LoggerFactory.getLogger(ResolutionRulesPlugin)
String configurationName = "resolutionRules"
Rules rules

public void apply(Project project) {
this.project = project
Configuration configuration = project.configurations.create(configurationName)
def extension = project.extensions.create('nebulaResolutionRules', NebulaResolutionRulesExtension)
project.afterEvaluate {
Rules rules = rulesFromConfiguration(configuration)
applyRules(rules, project, extension)

project.gradle.projectsEvaluated {
project.configurations.all{ Configuration config ->
if (config.name == configurationName) {
return
}
if (config.state != Configuration.State.UNRESOLVED) {
logger.warn("Configuration '{}' has been resolved. Dependency resolution rules will not be applied", config.name)
return
}
config.resolutionStrategy { ResolutionStrategy rs ->
getRules().configurationRules().each { ConfigurationRule rule ->
rule.apply(config)
}
getRules().resolutionRules().each { ResolutionRule rule ->
rule.apply(rs)
}
getRules().projectConfigurationRules().each { ProjectConfigurationRule rule ->
rule.apply(project, rs, config, extension)
}
}

}
getRules().projectRules().each { ProjectRule rule -> rule.apply(project) }
}
}

Rules getRules() {
if (!rules) {
rules = rulesFromConfiguration(project.configurations.getByName(configurationName))
}

rules
}

private Rules rulesFromConfiguration(Configuration configuration) {
List<Rules> rules = new ArrayList<Rules>();
Set<File> files = configuration.resolve()
Set<File> files = configuration.copyRecursive().resolve()
if (files.isEmpty()) {
logger.warn("No resolution rules have been added to the '{}' configuration", configuration.name)
}
Expand Down Expand Up @@ -103,21 +136,4 @@ class ResolutionRulesPlugin implements Plugin<Project> {
List<AlignRule> align = rules.collectMany { it.align }.flatten() as List<AlignRule>
return new Rules(replace: replace, substitute: substitute, reject: reject, deny: deny, align: align)
}

private void applyRules(Rules rules, Project project, NebulaResolutionRulesExtension extension) {
rules.projectRules().each { it.apply(project) }
project.configurations.all({ configuration ->
if (configuration.name == configurationName) {
return
}
if (configuration.state != Configuration.State.UNRESOLVED) {
logger.warn("Configuration '{}' has been resolved. Dependency resolution rules will not be applied", configuration.name)
return
}
rules.configurationRules().each {
it.apply(configuration)
}
rules.projectConfigurationRules().each { it.apply(project, configuration, extension) }
})
}
}

0 comments on commit a76cbcc

Please sign in to comment.