Skip to content

Commit 13ea20d

Browse files
committed
RUM-3100 Create plugin to generate verification-metadata.xml
1 parent 9d00117 commit 13ea20d

File tree

8 files changed

+227
-53
lines changed

8 files changed

+227
-53
lines changed

buildSrc/build.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ dependencies {
4444
implementation(libs.gson)
4545
implementation(libs.kotlinPoet)
4646

47+
// Verification Metadata XML
48+
implementation(libs.kotlinXmlBuilder)
49+
4750
// Tests
4851
testImplementation(libs.jUnit4)
4952
testImplementation(libs.mockitoKotlin)
@@ -70,6 +73,10 @@ gradlePlugin {
7073
id = "transitiveDependencies" // the alias
7174
implementationClass = "com.datadog.gradle.plugin.transdeps.TransitiveDependenciesPlugin"
7275
}
76+
register("verificationXml") {
77+
id = "verificationXml" // the alias
78+
implementationClass = "com.datadog.gradle.plugin.verification.VerificationXmlPlugin"
79+
}
7380
}
7481
}
7582

buildSrc/src/main/kotlin/com/datadog/gradle/config/MavenConfig.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,12 @@ fun Project.publishingConfig(
6565
url.set("https://www.apache.org/licenses/LICENSE-2.0")
6666
}
6767
}
68+
6869
organization {
6970
name.set("Datadog")
7071
url.set("https://www.datadoghq.com/")
7172
}
73+
7274
developers {
7375
developer {
7476
name.set("Datadog")
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2016-Present Datadog, Inc.
5+
*/
6+
7+
package com.datadog.gradle.plugin
8+
9+
import com.datadog.gradle.utils.execShell
10+
import org.gradle.api.DefaultTask
11+
import org.gradle.api.tasks.Internal
12+
import java.io.File
13+
14+
abstract class CheckGeneratedFileTask(
15+
@Internal val genTaskName: String
16+
) : DefaultTask() {
17+
18+
// region Task
19+
20+
fun verifyGeneratedFileExists(targetFile: File) {
21+
val lines = project.execShell(
22+
"git",
23+
"diff",
24+
"--color=never",
25+
"HEAD",
26+
"--",
27+
targetFile.absolutePath
28+
)
29+
30+
val additions = lines.filter { it.matches(Regex("^\\+[^+].*$")) }
31+
val removals = lines.filter { it.matches(Regex("^-[^-].*$")) }
32+
33+
if (additions.isNotEmpty() || removals.isNotEmpty()) {
34+
error(
35+
"Make sure you run the $genTaskName task before you push your PR.\n" +
36+
additions.joinToString("\n") +
37+
"\n" +
38+
removals.joinToString("\n")
39+
)
40+
}
41+
}
42+
43+
// endregion
44+
}

buildSrc/src/main/kotlin/com/datadog/gradle/plugin/apisurface/CheckApiSurfaceTask.kt

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66

77
package com.datadog.gradle.plugin.apisurface
88

9-
import com.datadog.gradle.utils.execShell
10-
import org.gradle.api.DefaultTask
9+
import com.datadog.gradle.plugin.CheckGeneratedFileTask
1110
import org.gradle.api.tasks.InputFile
1211
import org.gradle.api.tasks.InputFiles
1312
import org.gradle.api.tasks.TaskAction
1413
import java.io.File
1514

16-
open class CheckApiSurfaceTask : DefaultTask() {
15+
open class CheckApiSurfaceTask : CheckGeneratedFileTask(
16+
genTaskName = ApiSurfacePlugin.TASK_GEN_KOTLIN_API_SURFACE
17+
) {
1718

1819
@InputFile
1920
lateinit var kotlinSurfaceFile: File
@@ -30,33 +31,9 @@ open class CheckApiSurfaceTask : DefaultTask() {
3031

3132
@TaskAction
3233
fun applyTask() {
33-
verifySurfaceFile(kotlinSurfaceFile)
34+
verifyGeneratedFileExists(kotlinSurfaceFile)
3435
if (javaSurfaceFile.exists()) {
35-
verifySurfaceFile(javaSurfaceFile)
36-
}
37-
}
38-
39-
private fun verifySurfaceFile(surfaceFile: File) {
40-
val lines = project.execShell(
41-
"git",
42-
"diff",
43-
"--color=never",
44-
"HEAD",
45-
"--",
46-
surfaceFile.absolutePath
47-
)
48-
49-
val additions = lines.filter { it.matches(Regex("^\\+[^+].*$")) }
50-
val removals = lines.filter { it.matches(Regex("^-[^-].*$")) }
51-
52-
if (additions.isNotEmpty() || removals.isNotEmpty()) {
53-
error(
54-
"Make sure you run the ${ApiSurfacePlugin.TASK_GEN_KOTLIN_API_SURFACE} task" +
55-
" before you push your PR.\n" +
56-
additions.joinToString("\n") +
57-
"\n" +
58-
removals.joinToString("\n")
59-
)
36+
verifyGeneratedFileExists(javaSurfaceFile)
6037
}
6138
}
6239

buildSrc/src/main/kotlin/com/datadog/gradle/plugin/transdeps/CheckTransitiveDependenciesTask.kt

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66

77
package com.datadog.gradle.plugin.transdeps
88

9-
import com.datadog.gradle.utils.execShell
10-
import org.gradle.api.DefaultTask
9+
import com.datadog.gradle.plugin.CheckGeneratedFileTask
1110
import org.gradle.api.tasks.InputFile
1211
import org.gradle.api.tasks.TaskAction
1312
import java.io.File
1413

15-
open class CheckTransitiveDependenciesTask : DefaultTask() {
14+
open class CheckTransitiveDependenciesTask : CheckGeneratedFileTask(
15+
genTaskName = TransitiveDependenciesPlugin.TASK_GEN_TRANSITIVE_DEPS
16+
) {
1617

1718
@InputFile
1819
lateinit var dependenciesFile: File
@@ -26,27 +27,7 @@ open class CheckTransitiveDependenciesTask : DefaultTask() {
2627

2728
@TaskAction
2829
fun applyTask() {
29-
val lines = project.execShell(
30-
"git",
31-
"diff",
32-
"--color=never",
33-
"HEAD",
34-
"--",
35-
dependenciesFile.absolutePath
36-
)
37-
38-
val additions = lines.filter { it.matches(Regex("^\\+[^+].*$")) }
39-
val removals = lines.filter { it.matches(Regex("^-[^-].*$")) }
40-
41-
if (additions.isNotEmpty() || removals.isNotEmpty()) {
42-
error(
43-
"Make sure you run the ${TransitiveDependenciesPlugin.TASK_GEN_TRANSITIVE_DEPS} task" +
44-
" before you push your PR.\n" +
45-
additions.joinToString("\n") +
46-
"\n" +
47-
removals.joinToString("\n")
48-
)
49-
}
30+
verifyGeneratedFileExists(dependenciesFile)
5031
}
5132

5233
@InputFile
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2016-Present Datadog, Inc.
5+
*/
6+
7+
package com.datadog.gradle.plugin.verification
8+
9+
import com.datadog.gradle.config.AndroidConfig
10+
import org.gradle.api.DefaultTask
11+
import org.gradle.api.tasks.TaskAction
12+
import org.redundent.kotlin.xml.PrintOptions
13+
import org.redundent.kotlin.xml.xml
14+
import java.io.File
15+
import java.security.MessageDigest
16+
17+
open class GenerateVerificationXmlTask : DefaultTask() {
18+
19+
init {
20+
group = "datadog"
21+
description =
22+
"Generate the verification-metadata.xml for the artifact built from the module"
23+
}
24+
25+
private val md = MessageDigest.getInstance("SHA-256")
26+
27+
// region Task
28+
29+
@TaskAction
30+
fun applyTask() {
31+
val buildDir = project.layout.buildDirectory.asFile.get()
32+
val projectDir = project.layout.projectDirectory.asFile
33+
val publicationReleaseDir = File(File(buildDir, "publications"), "release")
34+
val outputFile = File(projectDir, VerificationXmlPlugin.XML_FILE_NAME)
35+
36+
val aarFile = File(File(File(buildDir, "outputs"), "aar"), "${project.name}-release.aar")
37+
val pomFile = File(publicationReleaseDir, "pom-default.xml")
38+
val moduleFile = File(publicationReleaseDir, "module.json")
39+
40+
val aarSha256 = aarFile.sha256()
41+
val pomSha256 = pomFile.sha256()
42+
val moduleSha256 = moduleFile.sha256()
43+
44+
val content = xml(TAG_ROOT) {
45+
xmlns = NS_DEPS_VERIF
46+
TAG_CONFIGURATION {
47+
TAG_VERIF_METADATA { -true.toString() }
48+
TAG_VERIF_SIGNATURE { -false.toString() } // TODO RUM-3104 add signature verification
49+
}
50+
TAG_COMPONENTS {
51+
TAG_COMPONENT {
52+
attribute(ATTR_GROUP, project.group)
53+
attribute(ATTR_NAME, project.name)
54+
attribute(ATTR_VERSION, AndroidConfig.VERSION.name)
55+
TAG_ARTIFACT {
56+
attribute(ATTR_NAME, "${project.name}-${AndroidConfig.VERSION.name}.aar")
57+
TAG_SHA256 {
58+
attribute(ATTR_VALUE, aarSha256)
59+
attribute(ATTR_ORIGIN, ORIGIN)
60+
}
61+
}
62+
TAG_ARTIFACT {
63+
attribute(ATTR_NAME, "${project.name}-${AndroidConfig.VERSION.name}.pom")
64+
TAG_SHA256 {
65+
attribute(ATTR_VALUE, pomSha256)
66+
attribute(ATTR_ORIGIN, ORIGIN)
67+
}
68+
}
69+
TAG_ARTIFACT {
70+
attribute(ATTR_NAME, "${project.name}-${AndroidConfig.VERSION.name}.module")
71+
TAG_SHA256 {
72+
attribute(ATTR_VALUE, moduleSha256)
73+
attribute(ATTR_ORIGIN, ORIGIN)
74+
}
75+
}
76+
}
77+
}
78+
}
79+
val xmlContent = content.toString(
80+
PrintOptions(
81+
indent = " ",
82+
pretty = true,
83+
singleLineTextElements = true
84+
)
85+
)
86+
outputFile.writeText(XML_PREFIX + xmlContent, Charsets.UTF_8)
87+
}
88+
89+
// endregion
90+
91+
// region Internal
92+
93+
fun File.sha256(): String {
94+
return md.digest(readBytes()).fold("", { str, byte -> str + "%02x".format(byte) })
95+
}
96+
97+
// endregion
98+
99+
companion object {
100+
101+
private const val NS_DEPS_VERIF = "https://schema.gradle.org/dependency-verification"
102+
private const val XML_PREFIX = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
103+
104+
private const val TAG_ROOT = "verification-metadata"
105+
private const val TAG_CONFIGURATION = "configuration"
106+
private const val TAG_VERIF_METADATA = "verify-metadata"
107+
private const val TAG_VERIF_SIGNATURE = "verify-signature"
108+
private const val TAG_COMPONENTS = "components"
109+
private const val TAG_COMPONENT = "component"
110+
private const val TAG_SHA256 = "sha256"
111+
112+
private const val TAG_ARTIFACT = "artifact"
113+
private const val ATTR_GROUP = "group"
114+
private const val ATTR_NAME = "name"
115+
private const val ATTR_VERSION = "version"
116+
private const val ATTR_VALUE = "value"
117+
private const val ATTR_ORIGIN = "origin"
118+
119+
private const val ORIGIN = "Datadog"
120+
}
121+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2016-Present Datadog, Inc.
5+
*/
6+
7+
package com.datadog.gradle.plugin.verification
8+
9+
import com.android.build.gradle.internal.tasks.factory.dependsOn
10+
import org.gradle.api.Plugin
11+
import org.gradle.api.Project
12+
13+
class VerificationXmlPlugin : Plugin<Project> {
14+
15+
override fun apply(target: Project) {
16+
val genTask = target.tasks.register(TASK_GEN_VERIFICATION_XML, GenerateVerificationXmlTask::class.java)
17+
18+
target.afterEvaluate {
19+
genTask.dependsOn("bundleReleaseAar")
20+
genTask.dependsOn("javaDocReleaseJar")
21+
genTask.dependsOn("sourceReleaseJar")
22+
genTask.dependsOn("generatePomFileForReleasePublication")
23+
genTask.dependsOn("generateMetadataFileForReleasePublication")
24+
// TODO RUM-3104 depends on "signReleasePublication"
25+
26+
getTasksByName("publishToSonatype", false).forEach {
27+
it.dependsOn(genTask)
28+
}
29+
getTasksByName("publishToMavenLocal", false).forEach {
30+
it.dependsOn(genTask)
31+
}
32+
}
33+
}
34+
35+
companion object {
36+
37+
const val TASK_GEN_VERIFICATION_XML = "generateVerificationXml"
38+
const val XML_FILE_NAME = "verification-metadata.xml"
39+
}
40+
}

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ kotlinAntlrRuntime = "v0.1.0"
7878
jsonSchemaValidator = "1.12.1"
7979
binaryCompatibility = "0.17.0"
8080
dependencyLicense = "0.3"
81+
kotlinXmlBuilder = "1.9.3"
8182

8283
# Integrations
8384
sqlDelight = "1.5.5"
@@ -220,6 +221,7 @@ kotlinSP = { module = "com.google.devtools.ksp:symbol-processing-api", version.r
220221
kotlinGrammarParser = { module = "com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin-jvm", version.ref = "kotlinGrammarParser" }
221222
kotlinAntlrRuntime = { module = "com.github.drieks.antlr-kotlin:antlr-kotlin-runtime", version.ref = "kotlinAntlrRuntime" }
222223
jsonSchemaValidator = { module = "com.github.everit-org.json-schema:org.everit.json.schema", version.ref = "jsonSchemaValidator" }
224+
kotlinXmlBuilder = {module="org.redundent:kotlin-xml-builder", version.ref="kotlinXmlBuilder"}
223225

224226
# Integrations
225227
sqlDelight = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqlDelight" }

0 commit comments

Comments
 (0)