diff --git a/.circleci/config.yml b/.circleci/config.yml index 7298a9aa5f..902b8644a1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -14,7 +14,7 @@ jobs: - run: name: Run Tests - command: ./gradlew clean check --parallel + command: ./gradlew clean check verifyVersionScan --parallel - save_cache: paths: diff --git a/buildSrc/src/main/groovy/VersionScanExtension.groovy b/buildSrc/src/main/groovy/VersionScanExtension.groovy index e4af437e9d..73136c0df6 100644 --- a/buildSrc/src/main/groovy/VersionScanExtension.groovy +++ b/buildSrc/src/main/groovy/VersionScanExtension.groovy @@ -6,4 +6,6 @@ class VersionScanExtension { boolean scanDependencies = false String legacyGroup String legacyModule + Map verifyPresent = Collections.emptyMap() + List verifyMissing = Collections.emptyList() } diff --git a/buildSrc/src/main/groovy/VersionScanPlugin.groovy b/buildSrc/src/main/groovy/VersionScanPlugin.groovy index abb2051f8d..13174602ec 100644 --- a/buildSrc/src/main/groovy/VersionScanPlugin.groovy +++ b/buildSrc/src/main/groovy/VersionScanPlugin.groovy @@ -34,19 +34,23 @@ class VersionScanPlugin implements Plugin { RepositorySystemSession session = newRepositorySystemSession(system) project.extensions.create("versionScan", VersionScanExtension) - project.task('scanVersions') { + def scanVersions = project.task('scanVersions') { description = "Queries for all versions of configured modules and finds key classes" } - if (!project.gradle.startParameter.taskNames.contains('scanVersions')) { + def hasRelevantTask = project.gradle.startParameter.taskNames.contains('scanVersions') + hasRelevantTask |= project.gradle.startParameter.taskNames.contains('scanVersionsReport') + hasRelevantTask |= project.gradle.startParameter.taskNames.contains('verifyVersionScan') + if (!hasRelevantTask) { return } - println "Adding scan tasks for $project" +// println "Adding scan tasks for $project" Set allInclude = Sets.newConcurrentHashSet() Set allExclude = Sets.newConcurrentHashSet() AtomicReference> keyPresent = new AtomicReference(Collections.emptySet()) AtomicReference> keyMissing = new AtomicReference(Collections.emptySet()) + def scanVersionsReport = project.task('scanVersionsReport') { description = "Prints the result of the scanVersions task" doLast { @@ -67,7 +71,9 @@ class VersionScanPlugin implements Plugin { } } } - project.tasks.scanVersions.finalizedBy(scanVersionsReport) + if (project.gradle.startParameter.taskNames.contains('scanVersions')) { + scanVersions.finalizedBy(scanVersionsReport) + } project.repositories { mavenCentral() @@ -118,6 +124,48 @@ class VersionScanPlugin implements Plugin { return } + Map verifyPresent = project.versionScan.verifyPresent + List verifyMissing = project.versionScan.verifyMissing + + if (!verifyPresent.isEmpty() || !verifyMissing.isEmpty()) { + def verifyVersionScan = project.task('verifyVersionScan') { + description = "Validates that the configured classes and methods are only present where expected." + doLast { + // This may already be done by the report task, but repeating for good measure. + keyPresent.get().removeAll(allExclude) + keyMissing.get().removeAll(allInclude) + + assert keyPresent.get() != [] || keyMissing.get() != [] + + def errors = [] + for (String className : verifyPresent.keySet()) { + String identifier = project.versionScan.scanMethods ? "$className|${verifyPresent.get(className)}" : className + if (!keyPresent.get().contains(identifier)) { + errors << "not a 'keyPresent' identifier: $identifier" + } + } + for (String className : verifyMissing) { + if (!keyMissing.get().contains(className)) { + errors << "not a 'keyMissing' identifier: $className" + } + } + errors.each { + System.err.println "Error for $group:$module - $it" + } + if (!errors.isEmpty()) { + throw new AssertionError("Version scan verification failed.\n" + + "Errors listed above are likely the result of a new module " + + "being published to Maven, not a code change in this repo.\n" + + "This does mean a fix should be made though to 'dd-trace-supported-framework.yaml'.") + } + } + } + + if (project.gradle.startParameter.taskNames.contains('scanVersions')) { + scanVersions.finalizedBy(verifyVersionScan) + } + } + // println "Scanning ${includeVersionSet.size()} included and ${excludeVersionSet.size()} excluded versions. Included: ${includeVersionSet.collect { it.version }}}" includeVersionSet.each { version -> @@ -144,12 +192,15 @@ class VersionScanPlugin implements Plugin { def jar = new JarFile(jarFile) for (jarEntry in jar.entries()) { if (jarEntry.name.endsWith(".class")) { + def className = jarEntry.name + className = className.replaceAll("/", ".") + className = className.replace(".class", "") if (project.versionScan.scanMethods) { findMethodNames(jar, jarEntry).each { - contentSet.add("$jarEntry.name|$it") + contentSet.add("$className|$it".toString()) } } else { - contentSet.add("$jarEntry.name") + contentSet.add(className) } } } @@ -163,7 +214,10 @@ class VersionScanPlugin implements Plugin { } } project.tasks.scanVersions.finalizedBy(task) - project.tasks.scanVersionsReport.mustRunAfter(task) + project.tasks.scanVersionsReport.dependsOn(task) + if (project.tasks.hasProperty("verifyVersionScan")) { + project.tasks.verifyVersionScan.dependsOn(task) + } } def filter(List list) { diff --git a/dd-java-agent/integrations/apache-httpclient/apache-httpclient.gradle b/dd-java-agent/integrations/apache-httpclient/apache-httpclient.gradle index 25b5e46b6c..31069f9af5 100644 --- a/dd-java-agent/integrations/apache-httpclient/apache-httpclient.gradle +++ b/dd-java-agent/integrations/apache-httpclient/apache-httpclient.gradle @@ -6,4 +6,8 @@ versionScan { versions = "[4.3,)" legacyGroup = "commons-httpclient" legacyModule = "commons-httpclient" + verifyPresent = [ + "org.apache.http.conn.SchemePortResolver": null, + "org.apache.http.conn.ssl.SSLContexts" : null, + ] } diff --git a/dd-java-agent/integrations/aws-sdk/aws-sdk.gradle b/dd-java-agent/integrations/aws-sdk/aws-sdk.gradle index 2b1270476f..fd6f0871d4 100644 --- a/dd-java-agent/integrations/aws-sdk/aws-sdk.gradle +++ b/dd-java-agent/integrations/aws-sdk/aws-sdk.gradle @@ -6,4 +6,9 @@ versionScan { group = "com.amazonaws" module = "aws-java-sdk-core" versions = "[1.11.0,)" + verifyPresent = [ + "com.amazonaws.http.client.HttpClientFactory" : null, + "com.amazonaws.http.apache.utils.ApacheUtils" : null, + "com.amazonaws.http.request.HttpRequestFactory": null, + ] } diff --git a/dd-java-agent/integrations/cassandra/cassandra.gradle b/dd-java-agent/integrations/cassandra/cassandra.gradle index a3385053c8..8f4d9ec8d5 100644 --- a/dd-java-agent/integrations/cassandra/cassandra.gradle +++ b/dd-java-agent/integrations/cassandra/cassandra.gradle @@ -4,4 +4,9 @@ versionScan { group = "com.datastax.cassandra" module = "cassandra-driver-core" versions = "[3.2,)" + verifyPresent = [ + "com.datastax.driver.core.utils.MoreObjects" : null, + "com.datastax.driver.core.RemoteEndpointAwareNettySSLOptions": null, + "com.datastax.driver.core.GuavaCompatibility" : null, + ] } diff --git a/dd-java-agent/integrations/jms/jms.gradle b/dd-java-agent/integrations/jms/jms.gradle index 48b056b9dc..6a3f280ac7 100644 --- a/dd-java-agent/integrations/jms/jms.gradle +++ b/dd-java-agent/integrations/jms/jms.gradle @@ -5,4 +5,8 @@ versionScan { module = "javax.jms-api" versions = "[2,)" legacyModule = "jms-api" + verifyPresent = [ + "javax.jms.JMSContext" : null, + "javax.jms.CompletionListener": null, + ] } diff --git a/dd-java-agent/integrations/mongo-async/mongo-async.gradle b/dd-java-agent/integrations/mongo-async/mongo-async.gradle index 118355e9b2..d3c2a164c4 100644 --- a/dd-java-agent/integrations/mongo-async/mongo-async.gradle +++ b/dd-java-agent/integrations/mongo-async/mongo-async.gradle @@ -4,4 +4,8 @@ versionScan { group = "org.mongodb" module = "mongodb-driver-async" versions = "[3.0,)" + verifyPresent = [ + "com.mongodb.operation.AsyncReadOperation": null, + "com.mongodb.client.model.MapReduceAction": null, + ] } diff --git a/dd-java-agent/integrations/mongo/mongo.gradle b/dd-java-agent/integrations/mongo/mongo.gradle index f13bde4197..ae44b1339c 100644 --- a/dd-java-agent/integrations/mongo/mongo.gradle +++ b/dd-java-agent/integrations/mongo/mongo.gradle @@ -4,4 +4,8 @@ versionScan { group = "org.mongodb" module = "mongo-java-driver" versions = "[3.0,)" + verifyPresent = [ + "com.mongodb.operation.AsyncReadOperation": null, + "com.mongodb.client.model.MapReduceAction": null, + ] } diff --git a/dd-java-agent/integrations/okhttp/okhttp.gradle b/dd-java-agent/integrations/okhttp/okhttp.gradle index 00c99173d7..4851f8a5d5 100644 --- a/dd-java-agent/integrations/okhttp/okhttp.gradle +++ b/dd-java-agent/integrations/okhttp/okhttp.gradle @@ -5,4 +5,9 @@ versionScan { module = "okhttp" versions = "[3.0,)" legacyGroup = "com.squareup.okhttp" + verifyPresent = [ + "okhttp3.Cookie" : null, + "okhttp3.ConnectionPool": null, + "okhttp3.Headers" : null, + ] } diff --git a/dd-java-agent/integrations/tomcat-embedded/tomcat-embedded.gradle b/dd-java-agent/integrations/tomcat-embedded/tomcat-embedded.gradle index 611bb99e02..db93b220bb 100644 --- a/dd-java-agent/integrations/tomcat-embedded/tomcat-embedded.gradle +++ b/dd-java-agent/integrations/tomcat-embedded/tomcat-embedded.gradle @@ -4,4 +4,9 @@ versionScan { group = "org.apache.tomcat.embed" module = "tomcat-embed-core" versions = "[8.0,)" + verifyPresent = [ + "org.apache.catalina.WebResource" : null, + "org.apache.catalina.webresources.TrackedInputStream" : null, + "org.apache.catalina.webresources.AbstractArchiveResource": null, + ] } diff --git a/dd-java-agent/integrations/tomcat/tomcat.gradle b/dd-java-agent/integrations/tomcat/tomcat.gradle index 5754356dd9..4f6ea77377 100644 --- a/dd-java-agent/integrations/tomcat/tomcat.gradle +++ b/dd-java-agent/integrations/tomcat/tomcat.gradle @@ -4,4 +4,9 @@ versionScan { group = "org.apache.tomcat" module = "tomcat-catalina" versions = "[8.0,)" + verifyPresent = [ + "org.apache.catalina.WebResource" : null, + "org.apache.catalina.webresources.TrackedInputStream" : null, + "org.apache.catalina.webresources.AbstractArchiveResource": null, + ] } diff --git a/dd-java-agent/src/main/resources/dd-trace-supported-framework.yaml b/dd-java-agent/src/main/resources/dd-trace-supported-framework.yaml index 789052d8b8..732c90e485 100644 --- a/dd-java-agent/src/main/resources/dd-trace-supported-framework.yaml +++ b/dd-java-agent/src/main/resources/dd-trace-supported-framework.yaml @@ -12,7 +12,6 @@ opentracing-apache-httpclient: supported_version: 4\.[3|4|5]\..* identifying_present_classes: - org.apache.http.conn.SchemePortResolver - - org.apache.http.config.Lookup - org.apache.http.conn.ssl.SSLContexts - artifact: commons-httpclient