Skip to content

Commit 2fab558

Browse files
ozzushSpace Team
authored andcommitted
Add Gradle metadata test
KTI-1321
1 parent edef21f commit 2fab558

File tree

43 files changed

+50230
-72
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+50230
-72
lines changed

repo/artifacts-tests/README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
# Artifacts Tests
22

3-
This module contains tests for changes in pom files for all maven artifacts we publish
3+
This module contains tests for changes in Maven and Gradle metadata for all maven artifacts we publish,
4+
as well as verifies the contents of the Kotlin distribution
45

5-
To reproduce locally build all artifacts first:
6+
To reproduce locally, first run:
67

78
```shell
8-
./gradlew clean install publish mvnPublish dist
9+
./gradlew clean install publish mvnPublish dist -Pteamcity=true
910
```
11+
12+
`-Pteamcity=true` is needed for Gradle metadata tests because the tests expect artifacts to contain metadata for Javadoc elements,
13+
which are only generated on CI.

repo/artifacts-tests/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
plugins {
22
kotlin("jvm")
3+
kotlin("plugin.serialization")
34
}
45

56
dependencies {
@@ -9,6 +10,7 @@ dependencies {
910
testImplementation(libs.junit.jupiter.api)
1011
testRuntimeOnly(libs.junit.jupiter.engine)
1112
testImplementation(projectTests(":compiler:tests-common-new"))
13+
testImplementation(libs.kotlinx.serialization.json)
1214
}
1315

1416
val defaultSnapshotVersion: String by extra
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package org.jetbrains.kotlin.code
7+
8+
import java.nio.file.Files
9+
import java.nio.file.Path
10+
import java.nio.file.Paths
11+
import java.nio.file.attribute.BasicFileAttributes
12+
import kotlin.io.path.extension
13+
import kotlin.streams.asSequence
14+
15+
val kotlinVersion: String = System.getProperty("kotlin.version")
16+
val mavenLocal: String = System.getProperty("maven.repo.local")
17+
val localRepoPath: Path = Paths.get(mavenLocal, "org/jetbrains/kotlin")
18+
val expectedRepoPath: Path = Paths.get("repo/artifacts-tests/src/test/resources/org/jetbrains/kotlin")
19+
20+
/**
21+
* Kotlin native bundles are present in TC artifacts but should not be checked until kotlin native enabled project-wide
22+
*/
23+
val nativeBundles = setOf(
24+
"kotlin-native",
25+
"kotlin-native-compiler-embeddable",
26+
"kotlin-native-prebuilt",
27+
)
28+
29+
val excludedProjects = setOf(
30+
"android-test-fixes",
31+
"annotation-processor-example",
32+
"gradle-warnings-detector",
33+
"kotlin-compiler-args-properties",
34+
"kotlin-gradle-plugin-tcs-android",
35+
"kotlin-gradle-subplugin-example",
36+
"kotlin-java-example",
37+
"kotlin-maven-plugin-test",
38+
"org.jetbrains.kotlin.gradle-subplugin-example.gradle.plugin",
39+
"org.jetbrains.kotlin.test.fixes.android.gradle.plugin",
40+
"org.jetbrains.kotlin.test.gradle-warnings-detector.gradle.plugin",
41+
"org.jetbrains.kotlin.test.kotlin-compiler-args-properties.gradle.plugin",
42+
)
43+
44+
/**
45+
* convert:
46+
* ${mavenLocal}/org/jetbrains/kotlin/artifact/version/artifact-version.ext
47+
* to:
48+
* ${expectedRepository}/org/jetbrains/kotlin/artifact/artifact.ext
49+
*/
50+
fun Path.toExpectedPath(): Path {
51+
val fileExtension = this.fileName.extension
52+
val artifactDirPath = localRepoPath.relativize(this).parent.parent
53+
val expectedFileName = "${artifactDirPath.fileName}.$fileExtension"
54+
return expectedRepoPath.resolve(artifactDirPath.resolve(expectedFileName))
55+
}
56+
57+
fun findActualArtifacts(extension: String, mustContainKotlinVersion: Boolean = false) = Files.find(
58+
localRepoPath,
59+
Integer.MAX_VALUE,
60+
{ path: Path, fileAttributes: BasicFileAttributes ->
61+
fileAttributes.isRegularFile
62+
&& "${path.fileName}".endsWith(extension, ignoreCase = true)
63+
&& if (mustContainKotlinVersion) path.contains(Paths.get(kotlinVersion)) else true
64+
}).asSequence()
65+
66+
fun findExpectedArtifacts(extension: String) = Files.find(
67+
expectedRepoPath,
68+
Integer.MAX_VALUE,
69+
{ path: Path, fileAttributes: BasicFileAttributes ->
70+
fileAttributes.isRegularFile
71+
&& "${path.fileName}".endsWith(extension, ignoreCase = true)
72+
}).asSequence()
73+
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
package org.jetbrains.kotlin.code
2+
3+
import kotlinx.serialization.Serializable
4+
import kotlinx.serialization.SerialName
5+
import org.jetbrains.kotlin.utils.addToStdlib.sequenceOfLazyValues
6+
7+
fun Sequence<Int>.firstNonZeroOrZero() = firstOrNull { it != 0 } ?: 0
8+
9+
private fun <T : Comparable<T>> compareLists(
10+
lhs: MutableList<T>,
11+
rhs: MutableList<T>,
12+
): Int {
13+
for (i in 0 until minOf(lhs.size, rhs.size)) {
14+
val cmp = lhs[i].compareTo(rhs[i])
15+
if (cmp != 0) return cmp
16+
}
17+
return lhs.size.compareTo(rhs.size)
18+
}
19+
20+
private fun <T : Comparable<T>> compareNullableLists(
21+
lhs: MutableList<T>?,
22+
rhs: MutableList<T>?,
23+
): Int {
24+
return when {
25+
lhs == null && rhs == null -> 0
26+
lhs == null -> -1
27+
rhs == null -> 1
28+
else -> compareLists(lhs, rhs)
29+
}
30+
}
31+
32+
33+
@Serializable
34+
data class GradleMetadata(
35+
val formatVersion: String,
36+
val component: Component,
37+
val createdBy: CreatedBy,
38+
val variants: MutableList<Variant>,
39+
) : Comparable<GradleMetadata> {
40+
fun setOrgGradleStatusAttributeToRelease() {
41+
component.attributes?.orgGradleStatus = "release"
42+
}
43+
44+
fun removeFilesFingerprint() {
45+
variants.forEach { it.removeFilesFingerprint() }
46+
}
47+
48+
fun sortListsRecursively() {
49+
variants.sort()
50+
variants.forEach { it.sortListsRecursively() }
51+
}
52+
53+
override fun compareTo(other: GradleMetadata): Int {
54+
return sequenceOf(
55+
compareValuesBy(this, other, { it.formatVersion }, { it.component }, { it.createdBy }),
56+
compareLists(this.variants, other.variants)
57+
).firstNonZeroOrZero()
58+
}
59+
}
60+
61+
@Serializable
62+
data class Component(
63+
val url: String? = null,
64+
val group: String,
65+
val module: String,
66+
val version: String,
67+
val attributes: ComponentAttributes? = null,
68+
) : Comparable<Component> {
69+
override fun compareTo(other: Component): Int {
70+
return compareValuesBy(
71+
this, other,
72+
{ it.url },
73+
{ it.group },
74+
{ it.module },
75+
{ it.version },
76+
{ it.attributes }
77+
)
78+
}
79+
}
80+
81+
@Serializable
82+
data class ComponentAttributes(
83+
@SerialName("org.gradle.status") var orgGradleStatus: String,
84+
) : Comparable<ComponentAttributes> {
85+
override fun compareTo(other: ComponentAttributes): Int {
86+
return compareValuesBy(this, other, { it.orgGradleStatus })
87+
}
88+
}
89+
90+
@Serializable
91+
data class CreatedBy(
92+
val gradle: Gradle,
93+
) : Comparable<CreatedBy> {
94+
override fun compareTo(other: CreatedBy): Int {
95+
return compareValuesBy(this, other, { it.gradle })
96+
}
97+
}
98+
99+
@Serializable
100+
data class Gradle(
101+
val version: String,
102+
) : Comparable<Gradle> {
103+
override fun compareTo(other: Gradle): Int {
104+
return compareValuesBy(this, other, { it.version })
105+
}
106+
}
107+
108+
@Serializable
109+
data class Variant(
110+
val name: String,
111+
val attributes: VariantAttributes,
112+
@SerialName("available-at") val availableAt: Component? = null,
113+
val dependencies: MutableList<Dependency>? = null,
114+
val dependencyConstraints: MutableList<Dependency>? = null,
115+
val files: MutableList<File>? = null,
116+
val capabilities: MutableList<Capability>? = null,
117+
) : Comparable<Variant> {
118+
fun removeFilesFingerprint() {
119+
files?.forEach { it.removeFingerprint() }
120+
}
121+
122+
fun sortListsRecursively() {
123+
dependencies?.sort()
124+
dependencies?.forEach { it.sortListsRecursively() }
125+
dependencyConstraints?.sort()
126+
dependencyConstraints?.forEach { it.sortListsRecursively() }
127+
files?.sort()
128+
capabilities?.sort()
129+
}
130+
131+
override fun compareTo(other: Variant): Int {
132+
return sequenceOfLazyValues(
133+
{
134+
compareValuesBy(
135+
this, other,
136+
{ it.name },
137+
{ it.attributes },
138+
{ it.availableAt }
139+
)
140+
},
141+
{ compareNullableLists(this.dependencies, other.dependencies) },
142+
{ compareNullableLists(this.dependencyConstraints, other.dependencyConstraints) },
143+
{ compareNullableLists(this.files, other.files) },
144+
{ compareNullableLists(this.capabilities, other.capabilities) },
145+
).firstOrNull { it != 0 } ?: 0
146+
}
147+
}
148+
149+
@Serializable
150+
data class VariantAttributes(
151+
@SerialName("org.gradle.category") val orgGradleCategory: String? = null,
152+
@SerialName("org.gradle.dependency.bundling") val orgGradleDependencyBundling: String? = null,
153+
@SerialName("org.gradle.docstype") val orgGradleDocstype: String? = null,
154+
@SerialName("org.gradle.usage") val orgGradleUsage: String? = null,
155+
@SerialName("org.gradle.jvm.environment") val orgGradleJvmEnvironment: String? = null,
156+
@SerialName("org.gradle.jvm.version") val orgGradleJvmVersion: Int? = null,
157+
@SerialName("org.gradle.libraryelements") val orgGradleLibraryelements: String? = null,
158+
@SerialName("org.gradle.plugin.api-version") val orgGradlePluginApiVersion: String? = null,
159+
@SerialName("org.jetbrains.kotlin.platform.type") val orgJetbrainsKotlinPlatformType: String? = null,
160+
@SerialName("org.jetbrains.kotlin.klib.packaging") val orgJetbrainsKotlinKlibPackaging: String? = null,
161+
@SerialName("org.jetbrains.kotlin.js.compiler") val orgJetbrainsKotlinJsCompiler: String? = null,
162+
@SerialName("org.jetbrains.kotlin.wasm.target") val orgJetbrainsKotlinWasmTarget: String? = null,
163+
) : Comparable<VariantAttributes> {
164+
override fun compareTo(other: VariantAttributes): Int {
165+
return compareValuesBy(
166+
this, other,
167+
{ it.orgGradleCategory },
168+
{ it.orgGradleDependencyBundling },
169+
{ it.orgGradleDocstype },
170+
{ it.orgGradleUsage },
171+
{ it.orgGradleJvmEnvironment },
172+
{ it.orgGradleJvmVersion },
173+
{ it.orgGradleLibraryelements },
174+
{ it.orgGradlePluginApiVersion },
175+
{ it.orgJetbrainsKotlinPlatformType },
176+
{ it.orgJetbrainsKotlinKlibPackaging },
177+
{ it.orgJetbrainsKotlinJsCompiler },
178+
{ it.orgJetbrainsKotlinWasmTarget }
179+
)
180+
}
181+
}
182+
183+
@Serializable
184+
data class Dependency(
185+
val group: String,
186+
val module: String,
187+
val version: Version,
188+
val attributes: DependencyAttributes? = null,
189+
val endorseStrictVersions: Boolean? = null,
190+
val excludes: MutableList<Exclude>? = null,
191+
val requestedCapabilities: MutableList<RequestedCapability>? = null,
192+
) : Comparable<Dependency> {
193+
fun sortListsRecursively() {
194+
excludes?.sort()
195+
requestedCapabilities?.sort()
196+
}
197+
198+
override fun compareTo(other: Dependency): Int {
199+
return sequenceOfLazyValues(
200+
{
201+
compareValuesBy(
202+
this, other,
203+
{ it.group },
204+
{ it.module },
205+
{ it.version },
206+
{ it.attributes },
207+
{ it.endorseStrictVersions }
208+
)
209+
},
210+
{ compareNullableLists(this.excludes, other.excludes) },
211+
{ compareNullableLists(this.requestedCapabilities, other.requestedCapabilities) },
212+
).firstNonZeroOrZero()
213+
}
214+
}
215+
216+
@Serializable
217+
data class Version(
218+
val requires: String,
219+
) : Comparable<Version> {
220+
override fun compareTo(other: Version): Int {
221+
return compareValuesBy(this, other, { it.requires })
222+
}
223+
}
224+
225+
@Serializable
226+
data class Exclude(
227+
val group: String,
228+
val module: String,
229+
) : Comparable<Exclude> {
230+
override fun compareTo(other: Exclude): Int {
231+
return compareValuesBy(this, other, { it.group }, { it.module })
232+
}
233+
}
234+
235+
@Serializable
236+
data class DependencyAttributes(
237+
@SerialName("org.gradle.category") val orgGradleCategory: String,
238+
) : Comparable<DependencyAttributes> {
239+
override fun compareTo(other: DependencyAttributes): Int {
240+
return compareValuesBy(this, other, { it.orgGradleCategory })
241+
}
242+
}
243+
244+
@Serializable
245+
data class RequestedCapability(
246+
val group: String,
247+
val name: String,
248+
) : Comparable<RequestedCapability> {
249+
override fun compareTo(other: RequestedCapability): Int {
250+
return compareValuesBy(this, other, { it.group }, { it.name })
251+
}
252+
}
253+
254+
@Serializable
255+
data class File(
256+
val name: String,
257+
val url: String,
258+
var size: Int?,
259+
var sha512: String?,
260+
var sha256: String?,
261+
var sha1: String?,
262+
var md5: String?,
263+
) : Comparable<File> {
264+
fun removeFingerprint() {
265+
size = null
266+
sha512 = null
267+
sha256 = null
268+
sha1 = null
269+
md5 = null
270+
}
271+
272+
override fun compareTo(other: File) = compareValuesBy(
273+
this, other,
274+
{ it.name },
275+
{ it.url },
276+
{ it.size },
277+
{ it.sha512 },
278+
{ it.sha256 },
279+
{ it.sha1 },
280+
{ it.md5 },
281+
)
282+
}
283+
284+
@Serializable
285+
data class Capability(
286+
val group: String,
287+
val name: String,
288+
val version: String,
289+
) : Comparable<Capability> {
290+
override fun compareTo(other: Capability): Int {
291+
return compareValuesBy(this, other, { it.group }, { it.name }, { it.version })
292+
}
293+
}

0 commit comments

Comments
 (0)