org.owasp.dependencycheck.gradle.tasks.AbstractAnalyze.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dependency-check-gradle Show documentation
Show all versions of dependency-check-gradle Show documentation
OWASP dependency-check gradle plugin is a software composition analysis tool used to find known vulnerable dependencies.
/*
* This file is part of dependency-check-gradle.
*
* 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.
*
* Copyright (c) 2015 Wei Ma. All Rights Reserved.
*/
package org.owasp.dependencycheck.gradle.tasks
import com.github.packageurl.PackageURL
import com.github.packageurl.PackageURLBuilder
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ModuleVersionIdentifier
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.gradle.api.artifacts.result.DependencyResult
import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.gradle.api.artifacts.result.ResolvedComponentResult
import org.gradle.api.artifacts.result.ResolvedDependencyResult
import org.gradle.api.attributes.Attribute
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
import org.gradle.util.GradleVersion
import org.owasp.dependencycheck.Engine
import org.owasp.dependencycheck.agent.DependencyCheckScanAgent
import org.owasp.dependencycheck.data.nexus.MavenArtifact
import org.owasp.dependencycheck.data.nvdcve.DatabaseException
import org.owasp.dependencycheck.dependency.Confidence
import org.owasp.dependencycheck.dependency.Dependency
import org.owasp.dependencycheck.dependency.IncludedByReference
import org.owasp.dependencycheck.dependency.Vulnerability
import org.owasp.dependencycheck.dependency.naming.CpeIdentifier
import org.owasp.dependencycheck.exception.ExceptionCollection
import org.owasp.dependencycheck.exception.ReportException
import org.owasp.dependencycheck.gradle.service.SlackNotificationSenderService
import org.owasp.dependencycheck.utils.SeverityUtil
import org.owasp.dependencycheck.utils.Checksum
import us.springett.parsers.cpe.CpeParser
import static org.owasp.dependencycheck.dependency.EvidenceType.PRODUCT
import static org.owasp.dependencycheck.dependency.EvidenceType.VENDOR
import static org.owasp.dependencycheck.reporting.ReportGenerator.Format
import static org.owasp.dependencycheck.utils.Checksum.*
/**
* Checks the projects dependencies for known vulnerabilities.
*/
//@groovy.transform.CompileStatic
abstract class AbstractAnalyze extends ConfiguredTask {
@Internal
String currentProjectName = project.getName()
@Internal
Attribute artifactType = Attribute.of('artifactType', String)
// @Internal
private static final GradleVersion CUTOVER_GRADLE_VERSION = GradleVersion.version("4.0")
private static final GradleVersion IGNORE_NON_RESOLVABLE_SCOPES_GRADLE_VERSION = GradleVersion.version("7.0")
/**
* Calls dependency-check-core's analysis engine to scan
* all of the projects dependencies.
*/
@TaskAction
@groovy.transform.CompileStatic
analyze() {
if (config.skip) {
logger.lifecycle("Skipping dependency-check-gradle")
return
}
verifySettings()
initializeSettings()
Engine engine = null
try {
engine = new Engine(settings)
} catch (DatabaseException ex) {
String msg = "Unable to connect to the dependency-check database"
if (config.failOnError) {
cleanup(engine)
throw new GradleException(msg, ex)
} else {
logger.error(msg)
}
}
if (engine != null) {
scanDependencies(engine)
ExceptionCollection exCol = null
logger.lifecycle("Checking for updates and analyzing dependencies for vulnerabilities")
try {
engine.analyzeDependencies()
} catch (ExceptionCollection ex) {
if (config.failOnError || ex.isFatal()) {
cleanup(engine)
throw new GradleException("Analysis failed.", ex)
}
exCol = ex
}
logger.lifecycle("Generating report for project ${currentProjectName}")
try {
String name = project.getName()
String displayName = determineDisplayName()
String groupId = project.getGroup()
String version = project.getVersion().toString()
File output = project.file(config.outputDirectory)
for (String f : getReportFormats(config.format, config.formats)) {
engine.writeReports(displayName, groupId, name, version, output, f, exCol)
}
showSummary(engine)
def result = checkForFailure(engine)
sendSlackNotification(result)
if (result.failed) {
throw new GradleException(result.msg)
}
} catch (ReportException ex) {
if (config.failOnError) {
if (exCol != null) {
exCol.addException(ex)
throw new GradleException("Error generating the report", exCol)
} else {
throw new GradleException("Error generating the report", ex)
}
} else {
logger.error("Error generating the report", ex)
}
} finally {
cleanup(engine)
}
if (config.failOnError && exCol != null && exCol.getExceptions().size() > 0) {
throw new GradleException("One or more exceptions occurred during analysis", exCol)
}
}
}
/**
* Gets the projects display name. Project.getDisplayName() has been
* introduced with Gradle 3.3, thus we need to check for the method's
* existence first. Fallback: use project NAME
* @return the display name
*/
String determineDisplayName() {
return project.metaClass.respondsTo(project, "getDisplayName") ? project.getDisplayName() : project.getName()
}
/**
* Verifies aspects of the configuration to ensure dependency-check can run correctly.
*/
@groovy.transform.CompileStatic
def verifySettings() {
if (!config.scanDependencies && !config.scanBuildEnv) {
throw new IllegalArgumentException("At least one of scanDependencies or scanBuildEnv must be set to true")
}
if (config.scanConfigurations && config.skipConfigurations) {
throw new IllegalArgumentException("you can only specify one of scanConfigurations or skipConfigurations")
}
if (config.scanProjects && config.skipProjects) {
throw new IllegalArgumentException("you can only specify one of scanProjects or skipProjects")
}
}
/**
* Combines the configured suppressionFile and suppressionFiles into a
* single array.
*
* @return an array of suppression file paths
*/
@groovy.transform.CompileStatic
private Set getReportFormats(String format, List formats) {
Set selectedFormats = new HashSet<>();
if (formats != null && !formats.isEmpty()) {
for (String f : formats) {
addFormat(f, selectedFormats)
}
}
addFormat(format, selectedFormats)
return selectedFormats;
}
@groovy.transform.CompileStatic
private void addFormat(String format, HashSet selectedFormats) {
if (format != null && !format.trim().isEmpty()) {
for (Format f : Format.values()) {
if (f.toString().equalsIgnoreCase(format)) {
selectedFormats.add(f.toString())
return;
}
}
//could be a custom report template...
selectedFormats.add(format);
}
}
/**
* Releases resources and removes temporary files used.
*/
@groovy.transform.CompileStatic
def cleanup(Engine engine) {
if (engine != null) {
engine.close()
}
if (settings != null) {
settings.cleanup(true)
}
}
/**
* Loads the projects dependencies into the dependency-check analysis engine.
*/
abstract scanDependencies(Engine engine)
/**
* Displays a summary of the dependency-check results to the build console.
*/
@groovy.transform.CompileStatic
def showSummary(Engine engine) {
def vulnerabilities = engine.getDependencies().collect { Dependency dependency ->
dependency.getVulnerabilities()
}.flatten()
logger.warn("Found ${vulnerabilities.size()} vulnerabilities in project ${currentProjectName}")
if (config.showSummary) {
DependencyCheckScanAgent.showSummary(project.name, engine.getDependencies());
}
}
/**
* If configured, fails the build if a vulnerability is identified with a CVSS
* score higher than the failure threshold configured.
*/
@groovy.transform.CompileStatic
CheckForFailureResult checkForFailure(Engine engine) {
if (config.failBuildOnCVSS > 10) {
return CheckForFailureResult.createSuccess()
}
Set vulnerabilities = new HashSet<>();
for (Dependency d : engine.getDependencies()) {
for (Vulnerability v : d.getVulnerabilities()) {
if ((v.getCvssV2() != null && v.getCvssV2().getCvssData() != null && v.getCvssV2().getCvssData().getBaseScore() >= config.failBuildOnCVSS)
|| (v.getCvssV3() != null && v.getCvssV3().getCvssData() != null && v.getCvssV3().getCvssData().getBaseScore() >= config.failBuildOnCVSS)
|| (v.getUnscoredSeverity() != null && SeverityUtil.estimateCvssV2(v.getUnscoredSeverity()) >= config.failBuildOnCVSS)
//safety net to fail on any if for some reason the above misses on 0
|| (config.failBuildOnCVSS <= 0.0f)) {
vulnerabilities.add(v.getName());
}
}
}
if (vulnerabilities.size() > 0) {
final String msg = String.format("%n%nDependency-Analyze Failure:%n"
+ "One or more dependencies were identified with vulnerabilities that have a CVSS score greater than '%.1f': %s%n"
+ "See the dependency-check report for more details.%n%n", config.failBuildOnCVSS, vulnerabilities.join(", "))
return CheckForFailureResult.createFailed(msg)
} else {
return CheckForFailureResult.createSuccess()
}
}
@groovy.transform.CompileStatic
void sendSlackNotification(CheckForFailureResult checkForFailureResult) {
if (checkForFailureResult.failed) {
new SlackNotificationSenderService(settings).send(getCurrentProjectName(), checkForFailureResult.msg)
}
}
@groovy.transform.CompileStatic
def static class CheckForFailureResult {
private Boolean failed
private String msg
CheckForFailureResult(Boolean failed, String msg) {
this.failed = failed
this.msg = msg
}
static CheckForFailureResult createSuccess() {
return new CheckForFailureResult(false, "")
}
static CheckForFailureResult createFailed(String msg) {
return new CheckForFailureResult(true, msg)
}
}
/**
* Checks whether the given project should be scanned
* because either scanProjects is empty or it contains the
* project's path.
*/
@groovy.transform.CompileStatic
def shouldBeScanned(Project project) {
!config.scanProjects || config.scanProjects.contains(project.path)
}
/**
* Checks whether the given project should be skipped
* because skipProjects contains the project's path.
*/
@groovy.transform.CompileStatic
def shouldBeSkipped(Project project) {
config.skipProjects.contains(project.path)
}
/**
* Checks whether the given configuration should be scanned
* because either scanConfigurations is empty or it contains the
* configuration's name.
*/
@groovy.transform.CompileStatic
boolean shouldBeScanned(Configuration configuration) {
!config.scanConfigurations || config.scanConfigurations.contains(configuration.name)
}
/**
* Checks whether the given configuration should be skipped
* because skipConfigurations contains the configuration's name.
*/
@groovy.transform.CompileStatic
boolean shouldBeSkipped(Configuration configuration) {
((IGNORE_NON_RESOLVABLE_SCOPES_GRADLE_VERSION.compareTo(GradleVersion.current()) <= 0 && (
"archives".equals(configuration.name) ||
"default".equals(configuration.name) ||
"runtime".equals(configuration.name) ||
"compile".equals(configuration.name) ||
"compileOnly".equals(configuration.name)))
|| config.skipConfigurations.contains(configuration.name))
}
/**
* Checks whether the given artifact should be skipped
* because skipGroups contains the artifact's group prefix.
*/
@groovy.transform.CompileStatic
def shouldBeSkipped(ResolvedArtifactResult artifact) {
def name = artifact.id.componentIdentifier.displayName
config.skipGroups.any { name.startsWith(it) }
}
/**
* Checks whether the given configuration should be skipped
* because it is a test configuration and skipTestGroups is true.
*/
@groovy.transform.CompileStatic
boolean shouldBeSkippedAsTest(Configuration configuration) {
config.skipTestGroups && isTestConfiguration(configuration)
}
/**
* Determines if the configuration should be considered a test configuration.
* @param configuration the configuration to insepct
* @return true if the configuration is considered a tet configuration; otherwise false
*/
@groovy.transform.CompileStatic
boolean isTestConfiguration(Configuration configuration) {
def isTestConfiguration = isTestConfigurationCheck(configuration)
def hierarchy = configuration.hierarchy.collect({ it.name }).join(" --> ")
logger.info("'{}' is considered a test configuration: {}", hierarchy, isTestConfiguration)
isTestConfiguration
}
/**
* Checks whether a configuration is considered to be a test configuration in order to skip it.
* A configuration is considered a test configuration if and only if any of the following conditions holds:
*
* - the name of the configuration or any of its parent configurations matches /((^|[a-z0-9_])T|(^|_)t)est([A-Z0-9_]|$)/
*
* The intent of the regular expression is to match `test` in a camel case or snake case configuration name.
*/
@groovy.transform.CompileStatic
static boolean isTestConfigurationCheck(Configuration configuration) {
boolean isTestConfiguration = configuration.name =~ /((^|[a-z0-9_])T|(^|_)t)est([A-Z0-9_]|$)/
configuration.hierarchy.each {
isTestConfiguration |= it.name ==~ /((^|[a-z0-9_])T|(^|_)t)est([A-Z0-9_]|$)/
}
isTestConfiguration
}
/**
* Determines if the onfiguration can be resolved
* @param configuration the configuration to inspect
* @return true if the configuration can be resolved; otherwise false
*/
@groovy.transform.CompileStatic
boolean canBeResolved(Configuration configuration) {
configuration.metaClass.respondsTo(configuration, "isCanBeResolved") ?
configuration.isCanBeResolved() : true
}
/**
* Process the incoming artifacts for the given project's configurations.
* @param project the project to analyze
* @param engine the dependency-check engine
*/
@groovy.transform.CompileStatic
protected void processBuildEnvironment(Project project, Engine engine) {
project.getBuildscript().configurations.findAll { Configuration configuration ->
shouldBeScanned(configuration) && !(shouldBeSkipped(configuration)
|| shouldBeSkippedAsTest(configuration)) && canBeResolved(configuration)
}.each { Configuration configuration ->
if (CUTOVER_GRADLE_VERSION.compareTo(GradleVersion.current()) > 0) {
processConfigLegacy configuration, engine
} else {
processConfigV4 project, configuration, engine, true
}
}
}
/**
* Process the incoming artifacts for the given project's configurations.
* @param project the project to analyze
* @param engine the dependency-check engine
*/
@groovy.transform.CompileStatic
protected void processConfigurations(Project project, Engine engine) {
project.configurations.findAll { Configuration configuration ->
shouldBeScanned(configuration) && !(shouldBeSkipped(configuration)
|| shouldBeSkippedAsTest(configuration)) && canBeResolved(configuration)
}.each { Configuration configuration ->
if (CUTOVER_GRADLE_VERSION.compareTo(GradleVersion.current()) > 0) {
processConfigLegacy configuration, engine
} else {
processConfigV4 project, configuration, engine
}
}
if (config.scanSet == null) {
List toScan = ['src/main/resources', 'src/main/webapp',
'./package.json', './package-lock.json',
'./npm-shrinkwrap.json', './yarn.lock',
'./pnpm.lock', './Gopkg.lock', './go.mod']
toScan.each {
File f = project.file it
if (f.exists()) {
engine.scan(f, project.name)
}
}
} else {
config.scanSet.each {
File f = project.file it
if (f.exists()) {
engine.scan(f, project.name)
} else {
logger.warn("ScanSet file `${f}` does not exist in ${project.name}")
}
}
}
config.additionalCpes.each {
var dependency = new Dependency(true);
dependency.setDescription(it.description)
dependency.setDisplayFileName(it.cpe);
dependency.setSha1sum(Checksum.getSHA1Checksum(it.cpe));
dependency.setSha256sum(Checksum.getSHA256Checksum(it.cpe));
dependency.setMd5sum(Checksum.getMD5Checksum(it.cpe));
dependency.addVulnerableSoftwareIdentifier(new CpeIdentifier(CpeParser.parse(it.cpe), Confidence.HIGHEST))
dependency.setFileName("")
dependency.setActualFilePath("")
engine.addDependency(dependency)
}
}
/**
* Process the incoming artifacts for the given project's configurations using APIs pre-gradle 4.0.
* @param project the project to analyze
* @param engine the dependency-check engine
*/
@groovy.transform.CompileStatic
protected void processConfigLegacy(Configuration configuration, Engine engine) {
configuration.getResolvedConfiguration().getResolvedArtifacts().collect { ResolvedArtifact artifact ->
def dependencies = engine.scan(artifact.getFile())
addInfoToDependencies(dependencies, configuration.name,
artifact.moduleVersion.getId(), null)
}
}
@groovy.transform.CompileStatic
private Map> buildIncludedByMap(Project project, Configuration configuration, boolean scanningBuildEnv) {
Map> includedByMap = new HashMap<>()
String type = null
if (scanningBuildEnv) {
type = 'buildEnv'
}
IncludedByReference parent = new IncludedByReference(convertIdentifier(project).toString(), type)
configuration.incoming.resolutionResult.root.getDependencies().forEach({
if (it instanceof ResolvedDependencyResult) {
ResolvedDependencyResult dr = (ResolvedDependencyResult) it
ResolvedComponentResult current = dr.selected
PackageURL purl = convertIdentifier(current)
if (includedByMap.containsKey(purl)) {
includedByMap.get(purl).add(parent)
} else {
Set rootParent = new HashSet<>()
rootParent.add(parent)
includedByMap.put(purl, rootParent)
}
IncludedByReference root = new IncludedByReference(convertIdentifier(current).toString(), type)
collectDependencyMap(includedByMap, root, current.getDependencies(), 0)
} else {
//TODO logging?
}
});
return includedByMap
}
@groovy.transform.CompileStatic
private static void collectDependencyMap(Map> includedByMap, IncludedByReference root, Set extends DependencyResult> dependencies, int depth) {
for (DependencyResult it : dependencies) {
if (it instanceof ResolvedDependencyResult) {
ResolvedDependencyResult rdr = (ResolvedDependencyResult) it
ResolvedComponentResult current = rdr.selected
PackageURL purl = convertIdentifier(current)
if (includedByMap.containsKey(purl)) {
// jackson-bom ends up creating an infinite loop so check if we've been here before
// https://github.com/dependency-check/dependency-check-gradle/issues/307
Set includedBy = includedByMap.get(purl)
if (includedBy.contains(root)) {
continue;
}
includedBy.add(root)
} else {
Set rootParent = new HashSet<>()
rootParent.add(root)
includedByMap.put(purl, rootParent);
}
if (current.getDependencies() != null && !current.getDependencies().isEmpty() && depth < 500) {
collectDependencyMap(includedByMap, root, current.getDependencies(), depth + 1)
}
}
}
}
/**
* Process the incoming artifacts for the given project's configurations using APIs introduced in gradle 4.0+.
* @param project the project to analyze
* @param configuration a particular configuration of the project to analyze
* @param engine the dependency-check engine
* @param scanningBuildEnv true if scanning the build environment; otherwise false
*/
protected void processConfigV4(Project project, Configuration configuration, Engine engine, boolean scanningBuildEnv = false) {
String projectName = project.name
String scope = "$projectName:$configuration.name"
if (scanningBuildEnv) {
scope += " (buildEnv)"
}
logger.info "- Analyzing ${scope}"
Map componentVersions = [:]
configuration.incoming.resolutionResult.allDependencies.each {
if (it.hasProperty('selected')) {
componentVersions.put(it.selected.id.toString(), it.selected.moduleVersion)
} else if (it.hasProperty('attempted')) {
logger.debug("Unable to resolve artifact in ${it.attempted.displayName}")
} else {
logger.warn("Unable to resolve: ${it}")
}
}
Map> includedByMap = buildIncludedByMap(project, configuration, scanningBuildEnv)
def types = config.analyzedTypes
for (String type : types) {
List rar = configuration.incoming.artifactView {
lenient true
attributes {
it.attribute(artifactType, type)
}
}.getArtifacts().toList();
for (ResolvedArtifactResult resolvedArtifactResult : rar) {
if (shouldBeSkipped(resolvedArtifactResult)) {
continue;
}
ModuleVersionIdentifier id = componentVersions[resolvedArtifactResult.id.componentIdentifier.getDisplayName()]
if (id == null) {
logger.debug "Could not find dependency {'artifact': '${resolvedArtifactResult.id.componentIdentifier}', " +
"'file':'${resolvedArtifactResult.file}'}"
} else {
def deps = engine.scan(resolvedArtifactResult.file, scope)
if (deps != null) {
addInfoToDependencies(deps, scope, id, includedByMap.get(convertIdentifier(id)))
}
}
}
}
}
/**
* Adds additional information and evidence to the dependencies.
* @param deps the list of dependencies that will be updated
* @param configurationName the configuration name that the artifact was identified in
* @param group the group id for the artifact coordinates
* @param artifact the artifact id for the artifact coordinates
* @param version the version number for the artifact coordinates
*/
@groovy.transform.CompileStatic
protected void addInfoToDependencies(List deps, String configurationName,
ModuleVersionIdentifier id, Set includedBy) {
if (deps != null) {
if (deps.size() == 1) {
def d = deps.get(0)
MavenArtifact mavenArtifact = new MavenArtifact(id.group, id.name, id.version)
d.addAsEvidence("gradle", mavenArtifact, Confidence.HIGHEST)
d.addProjectReference(configurationName)
if (includedBy != null) {
d.addAllIncludedBy(includedBy)
}
} else {
for (Dependency it : deps) {
it.addProjectReference(configurationName)
if (includedBy != null) {
it.addAllIncludedBy(includedBy)
}
}
}
}
}
@groovy.transform.CompileStatic
private static PackageURL convertIdentifier(Project project) {
final PackageURL p
if (project.group) {
p = new PackageURL("maven", project.group.toString(),
project.name, project.version.toString(), null, null)
} else {
p = PackageURLBuilder.aPackageURL().withType("gradle")
.withName(project.name).withVersion(project.version.toString()).build()
}
return p;
}
@groovy.transform.CompileStatic
private static PackageURL convertIdentifier(ResolvedComponentResult result) {
ModuleVersionIdentifier id = result.getModuleVersion()
PackageURL p
if (id.group) {
p = new PackageURL("maven", id.group,
id.name, id.version, null, null)
} else {
PackageURLBuilder pb = PackageURLBuilder.aPackageURL().withType("gradle")
.withName(id.name)
if (id.version) {
pb.withVersion(id.version)
}
p = pb.build()
}
return p;
}
@groovy.transform.CompileStatic
private static PackageURL convertIdentifier(ModuleComponentIdentifier id) {
final PackageURL p = new PackageURL("maven", id.moduleIdentifier.group,
id.moduleIdentifier.name, id.version, null, null);
return p;
}
@groovy.transform.CompileStatic
private static PackageURL convertIdentifier(ProjectComponentIdentifier id) {
return PackageURLBuilder.aPackageURL().withType("gradle").withName(id.projectPath).build()
}
@groovy.transform.CompileStatic
private static PackageURL convertIdentifier(ModuleVersionIdentifier id) {
PackageURL p
if (id.group) {
p = new PackageURL("maven", id.group,
id.name, id.version, null, null);
} else {
PackageURLBuilder pb = PackageURLBuilder.aPackageURL().withType("gradle")
.withName(id.name)
if (id.version) {
pb.withVersion(id.version)
}
}
return p;
}
/**
* Adds a dependency to the engine. This is used when an artifact is scanned that is not
* supported by dependency-check (different dependency type for possibly new language).
* @param engine a reference to the engine
* @param projectName the project name
* @param configurationName the configuration name
* @param group the group id
* @param name the name or artifact id
* @param version the version number
* @param displayName the display name
*/
@groovy.transform.CompileStatic
protected void addDependency(Engine engine, String projectName, String configurationName,
ModuleVersionIdentifier id, String displayName, File file = null) {
//id.group, id.name, id.version,
String display = displayName ?: "${id.group}:${id.name}:${id.version}"
Dependency dependency
String sha256
if (file == null) {
logger.debug("Adding virtual dependency for ${display}")
dependency = new Dependency(project.buildFile, true)
} else {
logger.debug("Adding dependency for ${display}")
dependency = new Dependency(file)
}
if (dependency.sha1sum == null && dependency.virtual) {
dependency.sha1sum = getSHA1Checksum("${id.group}:${id.name}:${id.version}")
dependency.sha256sum = getSHA256Checksum("${id.group}:${id.name}:${id.version}")
dependency.md5sum = getMD5Checksum("${id.group}:${id.name}:${id.version}")
dependency.displayFileName = display
}
dependency.addEvidence(VENDOR, "build.gradle", "displayName", display, Confidence.MEDIUM)
dependency.addEvidence(PRODUCT, "build.gradle", "displayName", display, Confidence.HIGH)
if (dependency.packagePath == null) {
dependency.name = id.name
dependency.version = id.version
dependency.packagePath = "${id.group}:${id.name}:${id.version}"
}
MavenArtifact mavenArtifact = new MavenArtifact(id.group, id.name, id.version)
dependency.addAsEvidence("gradle", mavenArtifact, Confidence.HIGHEST)
dependency.addProjectReference("${projectName}:${configurationName}")
engine.addDependency(dependency)
}
/**
* Check if the notCompatibleWithConfigurationCache method exists in the class.
* @return true if it exists; false otherwise.
*/
@groovy.transform.CompileStatic
protected boolean hasNotCompatibleWithConfigurationCacheOption() {
return metaClass.respondsTo(this, "notCompatibleWithConfigurationCache", String)
}
/**
* Calls notCompatibleWithConfigurationCache method in order to avoid failures when
* Gradle configuration cache is enabled.
*/
@groovy.transform.CompileStatic
protected void callIncompatibleWithConfigurationCache() {
String methodName = "notCompatibleWithConfigurationCache"
Object[] methodArgs = ["The gradle-versions-plugin isn't compatible with the configuration cache"]
metaClass.invokeMethod(this, methodName, methodArgs)
}
}