diff --git a/.ci/ci.sh b/.ci/ci.sh index 5c63f91e10..32937655e4 100755 --- a/.ci/ci.sh +++ b/.ci/ci.sh @@ -1,7 +1,7 @@ #!/bin/bash # Do the Gradle build -./gradlew --scan build --build-cache || exit 1 +./gradlew build --build-cache || exit 1 ./gradlew npmTest --build-cache || exit 1 if [ "$TRAVIS_REPO_SLUG" == "diffplug/spotless" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_BRANCH" == "master" ]; then diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 699e9df5ae..36a989760b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -145,6 +145,7 @@ pluginManagement { In Gradle 6.0+, you can use the following snippet in your `settings.gradle`. + ```gradle pluginManagement { repositories { @@ -159,12 +160,15 @@ pluginManagement { resolutionStrategy { eachPlugin { if (requested.id.id == 'com.diffplug.gradle.spotless') { - useModule('com.github.{{user-or-org}}.spotless:spotless-plugin-gradle:SHA_OF_COMMIT_YOU_WANT') + useModule('com.github.{{USER_OR_ORG}}.spotless:spotless-plugin-gradle:{{SHA_OF_COMMIT_YOU_WANT}}') } } } } ``` + +If it doesn't work, you can check the JitPack log at `https://jitpack.io/com/github/{{USER_OR_ORG}}/spotless/{{SHA_OF_COMMIT_YOU_WANT}}/build.log`. + ### Maven Run `./gradlew publishToMavenLocal` to publish this to your local repository. The maven plugin is not published to JitPack due to [jitpack/jitpack.io#4112](https://github.com/jitpack/jitpack.io/issues/4112). diff --git a/build.gradle b/build.gradle index 106a6ab335..ae0aa5e42d 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,6 @@ plugins { id 'com.diffplug.gradle.eclipse.resourcefilters' version '3.18.1' // https://plugins.gradle.org/plugin/com.gradle.plugin-publish id 'com.gradle.plugin-publish' version '0.10.1' apply false - // https://plugins.gradle.org/plugin/com.gradle.build-scan - id 'com.gradle.build-scan' version '2.4' // https://github.com/bintray/gradle-bintray-plugin/releases id 'com.jfrog.bintray' version '1.8.4' apply false // https://github.com/mnlipp/jdrupes-mdoclet/releases @@ -17,11 +15,6 @@ plugins { id "com.github.spotbugs" version "2.0.0" apply false } -buildScan { - termsOfServiceUrl = 'https://gradle.com/terms-of-service' - apply from: 'gradle/build-scans.gradle' -} - // root eclipse project apply plugin: 'com.diffplug.gradle.eclipse.resourcefilters' eclipseResourceFilters { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 87b738cbd0..5c2d1cf016 100755 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f04d6a20ae..94920145f3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index af6708ff22..83f2acfdc3 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m"' +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -109,8 +125,8 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` diff --git a/gradlew.bat b/gradlew.bat index 6d57edc706..9618d8d960 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index f3801fa46c..8c5a30793b 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,7 +3,9 @@ ### Version 3.27.0-SNAPSHOT - TBD ([javadoc](https://diffplug.github.io/spotless/javadoc/snapshot/), [snapshot](https://oss.sonatype.org/content/repositories/snapshots/com/diffplug/spotless/spotless-plugin-gradle/)) * Added method `FormatExtension.createIndependentTask(String taskName)` which allows creating a Spotless task outside of the `check`/`apply` lifecycle. See [javadoc](https://github.com/diffplug/spotless/blob/91ed7203994e52058ea6c2e0f88d023ed290e433/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java#L613-L639) for details. ([#500](https://github.com/diffplug/spotless/pull/500)) -* Running clean and spotlessCheck during a parallel build could cause exceptions, fixed by ([#501](https://github.com/diffplug/spotless/pull/501)). +* Running `clean` and `spotlessCheck` during a parallel build could cause exceptions, fixed by ([#501](https://github.com/diffplug/spotless/pull/501)). +* Fixed Gradle 7 deprecation warnings that started being emitted in Gradle 6. ([#503](https://github.com/diffplug/spotless/pull/503)) + * Even if you're using a pre-6.0 version of Gradle, you will probably see small performance and stability improvements. The PR above finally fixed the root problems of ([#372](https://github.com/diffplug/spotless/issues/372)). ### Version 3.26.1 - November 27th 2019 ([javadoc](https://diffplug.github.io/spotless/javadoc/spotless-plugin-gradle/3.26.1/), [jcenter](https://bintray.com/diffplug/opensource/spotless-plugin-gradle/3.26.1)) diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java index 3723d89526..753b3fd280 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java @@ -603,6 +603,9 @@ protected void setupTask(SpotlessTask task) { } task.setSteps(steps); task.setLineEndingsPolicy(getLineEndings().createPolicy(getProject().getProjectDir(), () -> task.target)); + if (root.project != root.project.getRootProject()) { + root.registerDependenciesTask.hookSubprojectTask(task); + } } /** Returns the project that this extension is attached to. */ diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GradleProvisioner.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GradleProvisioner.java index 57ee601de9..218dfb2a2f 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GradleProvisioner.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GradleProvisioner.java @@ -15,16 +15,21 @@ */ package com.diffplug.gradle.spotless; +import java.io.File; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.ConfigurationContainer; import org.gradle.api.artifacts.Dependency; -import com.diffplug.common.base.StringPrinter; +import com.diffplug.common.base.Preconditions; +import com.diffplug.common.collect.ImmutableList; import com.diffplug.spotless.Provisioner; /** Gradle integration for Provisioner. */ @@ -32,6 +37,35 @@ public class GradleProvisioner { private GradleProvisioner() {} public static Provisioner fromProject(Project project) { + // TODO: this method is not necessary - we could remove it entirely for a small speedup + return project.getPlugins().apply(SpotlessPlugin.class).getExtension().registerDependenciesTask.rootProvisioner; + } + + /** The provisioner used for the root project. */ + static class RootProvisioner implements Provisioner { + private final Project rootProject; + private final Map> cache = new HashMap<>(); + + RootProvisioner(Project rootProject) { + Preconditions.checkArgument(rootProject == rootProject.getRootProject()); + this.rootProject = rootProject; + } + + @Override + public Set provisionWithTransitives(boolean withTransitives, Collection mavenCoordinates) { + Request req = new Request(withTransitives, mavenCoordinates); + Set result = cache.get(req); + if (result != null) { + return result; + } else { + result = GradleProvisioner.fromRootBuildscript(rootProject).provisionWithTransitives(req.withTransitives, req.mavenCoords); + cache.put(req, result); + return result; + } + } + } + + static Provisioner fromRootBuildscript(Project project) { Objects.requireNonNull(project); return (withTransitives, mavenCoords) -> { try { @@ -39,21 +73,15 @@ public static Provisioner fromProject(Project project) { .map(project.getBuildscript().getDependencies()::create) .toArray(Dependency[]::new); - // #372 workaround: Accessing rootProject.configurations from multiple projects is not thread-safe - ConfigurationContainer configContainer; - synchronized (project.getRootProject()) { - configContainer = project.getRootProject().getBuildscript().getConfigurations(); - } - Configuration config = configContainer.detachedConfiguration(deps); + Configuration config = project.getRootProject().getBuildscript().getConfigurations().detachedConfiguration(deps); config.setDescription(mavenCoords.toString()); config.setTransitive(withTransitives); return config.resolve(); } catch (Exception e) { - logger.log(Level.SEVERE, - StringPrinter.buildStringFromLines("You probably need to add a repository containing the '" + mavenCoords + "' artifact in the 'build.gradle' of your root project.", + logger.log( + Level.SEVERE, + "You probably need to add a repository containing the '" + mavenCoords + "' artifact in the 'build.gradle' of your root project.\n" + "E.g.: 'buildscript { repositories { mavenCentral() }}'", - "Note that included buildscripts (using 'apply from') do not share their buildscript repositories with the underlying project.", - "You have to specify the missing repository explicitly in the buildscript of the root project."), e); throw e; } @@ -62,4 +90,44 @@ public static Provisioner fromProject(Project project) { private static final Logger logger = Logger.getLogger(GradleProvisioner.class.getName()); + /** Models a request to the provisioner. */ + private static class Request { + final boolean withTransitives; + final ImmutableList mavenCoords; + + public Request(boolean withTransitives, Collection mavenCoords) { + this.withTransitives = withTransitives; + this.mavenCoords = ImmutableList.copyOf(mavenCoords); + } + + @Override + public int hashCode() { + return withTransitives ? mavenCoords.hashCode() : ~mavenCoords.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof Request) { + Request o = (Request) obj; + return o.withTransitives == withTransitives && o.mavenCoords.equals(mavenCoords); + } else { + return false; + } + } + + @Override + public String toString() { + String coords = mavenCoords.toString(); + StringBuilder builder = new StringBuilder(); + builder.append(coords.substring(1, coords.length() - 1)); // strip off [] + if (withTransitives) { + builder.append(" with transitives"); + } else { + builder.append(" no transitives"); + } + return builder.toString(); + } + } } diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java index e435b46f45..cb9effbfd5 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java @@ -178,7 +178,7 @@ protected void setupTask(SpotlessTask task) { if (target == null) { JavaPluginConvention javaPlugin = getProject().getConvention().findPlugin(JavaPluginConvention.class); if (javaPlugin == null) { - throw new GradleException("You must apply the java plugin before the spotless plugin if you are using the java extension."); + throw new GradleException("You must either specify 'target' manually or apply the 'java' plugin."); } FileCollection union = getProject().files(); for (SourceSet sourceSet : javaPlugin.getSourceSets()) { diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/RegisterDependenciesTask.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/RegisterDependenciesTask.java new file mode 100644 index 0000000000..1284d7f372 --- /dev/null +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/RegisterDependenciesTask.java @@ -0,0 +1,97 @@ +/* + * Copyright 2016 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.gradle.spotless; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import org.gradle.api.DefaultTask; +import org.gradle.api.execution.TaskExecutionGraph; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.TaskAction; + +import com.diffplug.common.base.Preconditions; +import com.diffplug.common.io.Files; +import com.diffplug.spotless.FormatterStep; + +/** + * NOT AN END-USER TASK, DO NOT USE FOR ANYTHING! + * + * - When a user asks for a formatter, we need to download the jars for that formatter + * - Gradle wants us to resolve all our dependencies in the root project - no new dependencies in subprojects + * - So, whenever a SpotlessTask in a subproject gets configured, we call {@link #hookSubprojectTask(SpotlessTask)}, + * which makes this task a dependency of the SpotlessTask + * - When this "registerDependencies" task does its up-to-date check, it queries the task execution graph to see which + * SpotlessTasks are at risk of being executed, and causes them all to be evaluated safely in the root buildscript. + */ +public class RegisterDependenciesTask extends DefaultTask { + static final String TASK_NAME = "spotlessInternalRegisterDependencies"; + + @Input + public List getSteps() { + List allSteps = new ArrayList<>(); + TaskExecutionGraph taskGraph = getProject().getGradle().getTaskGraph(); + for (SpotlessTask task : tasks) { + if (taskGraph.hasTask(task)) { + allSteps.addAll(task.getSteps()); + } + } + return allSteps; + } + + private List tasks = new ArrayList<>(); + + @Internal + public List getTasks() { + return tasks; + } + + void hookSubprojectTask(SpotlessTask task) { + tasks.add(task); + task.dependsOn(this); + } + + File unitOutput; + + @OutputFile + public File getUnitOutput() { + return unitOutput; + } + + GradleProvisioner.RootProvisioner rootProvisioner; + + @Internal + public GradleProvisioner.RootProvisioner getRootProvisioner() { + return rootProvisioner; + } + + void setup() { + Preconditions.checkArgument(getProject().getRootProject() == getProject(), "Can only be used on the root project"); + unitOutput = new File(getProject().getBuildDir(), "tmp/spotless-register-dependencies"); + rootProvisioner = new GradleProvisioner.RootProvisioner(getProject()); + } + + @TaskAction + public void trivialFunction() throws IOException { + Files.createParentDirs(unitOutput); + Files.write(Integer.toString(getSteps().size()), unitOutput, StandardCharsets.UTF_8); + } +} diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java index 7d34a93caa..1221872c06 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java @@ -39,6 +39,7 @@ public class SpotlessExtension { final Project project; final Task rootCheckTask, rootApplyTask; + final RegisterDependenciesTask registerDependenciesTask; static final String EXTENSION = "spotless"; static final String CHECK = "Check"; @@ -58,6 +59,12 @@ public SpotlessExtension(Project project) { rootApplyTask = project.task(EXTENSION + APPLY); rootApplyTask.setGroup(TASK_GROUP); rootApplyTask.setDescription(APPLY_DESCRIPTION); + if (project.getRootProject() == project) { + registerDependenciesTask = project.getTasks().create(RegisterDependenciesTask.TASK_NAME, RegisterDependenciesTask.class); + registerDependenciesTask.setup(); + } else { + registerDependenciesTask = project.getRootProject().getPlugins().apply(SpotlessPlugin.class).spotlessExtension.registerDependenciesTask; + } } /** Line endings (if any). */ diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/RegisterDependenciesTaskTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/RegisterDependenciesTaskTest.java new file mode 100644 index 0000000000..2e4e0f40c0 --- /dev/null +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/RegisterDependenciesTaskTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2016 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.gradle.spotless; + +import java.io.IOException; + +import org.assertj.core.api.Assertions; +import org.junit.Test; + +public class RegisterDependenciesTaskTest extends GradleIntegrationTest { + @Test + public void registerDependencies() throws IOException { + setFile("settings.gradle") + .toLines("include 'sub'"); + setFile("build.gradle").toLines( + "buildscript { repositories { mavenCentral() } }", + "plugins { id 'com.diffplug.gradle.spotless' }"); + setFile("sub/build.gradle").toLines( + "apply plugin: 'com.diffplug.gradle.spotless'", + "", + "spotless {", + " java {", + " target 'src/main/java/**/*.java'", + " googleJavaFormat('1.2')", + " }", + "}"); + + String oldestSupported = gradleRunner() + .withArguments("spotlessCheck").build().getOutput(); + Assertions.assertThat(oldestSupported.replace("\r", "")).startsWith( + ":spotlessCheck UP-TO-DATE\n" + + ":spotlessInternalRegisterDependencies\n" + + ":sub:spotlessJava\n" + + ":sub:spotlessJavaCheck\n" + + ":sub:spotlessCheck\n" + + "\n" + + "BUILD SUCCESSFUL"); + + setFile("gradle.properties").toLines(); + String newestSupported = gradleRunner().withGradleVersion("6.0") + .withArguments("spotlessCheck").build().getOutput(); + Assertions.assertThat(newestSupported.replace("\r", "")).startsWith( + "> Task :spotlessCheck UP-TO-DATE\n" + + "> Task :spotlessInternalRegisterDependencies\n" + + "> Task :sub:spotlessJava\n" + + "> Task :sub:spotlessJavaCheck\n" + + "> Task :sub:spotlessCheck\n" + + "\n" + + "BUILD SUCCESSFUL"); + } +} diff --git a/plugin-maven/build.gradle b/plugin-maven/build.gradle index c5a3c87759..c2aa5a4bb1 100644 --- a/plugin-maven/build.gradle +++ b/plugin-maven/build.gradle @@ -58,14 +58,14 @@ def mvnw(String args) { dependencies { if (!project.versionMaven.endsWith('-SNAPSHOT') && project.versionLib.endsWith('-SNAPSHOT')) { // gradle = release, lib = snapshot, therefore gradle should depend on the last stable lib - compile "com.diffplug.spotless:spotless-lib:${project.stableLib}" - compile "com.diffplug.spotless:spotless-lib-extra:${project.stableLib}" + implementation "com.diffplug.spotless:spotless-lib:${project.stableLib}" + implementation "com.diffplug.spotless:spotless-lib-extra:${project.stableLib}" } else { - compile project(':lib') - compile project(':lib-extra') + implementation project(':lib') + implementation project(':lib-extra') } - compile "org.codehaus.plexus:plexus-resources:${VER_PLEXUS_RESOURCES}" + implementation "org.codehaus.plexus:plexus-resources:${VER_PLEXUS_RESOURCES}" compileOnly "org.apache.maven:maven-plugin-api:${VER_MAVEN_API}" compileOnly "org.apache.maven.plugin-tools:maven-plugin-annotations:${VER_MAVEN_API}" @@ -135,7 +135,7 @@ libs.each { task createPomXml(dependsOn: installLocalDependencies) { doLast { - def additionalDependencies = project.configurations.compile.resolvedConfiguration.resolvedArtifacts.findAll { + def additionalDependencies = project.configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts.findAll { return !libs.contains(it.moduleVersion.id.name) }.collect { return " \n" +