Skip to content

Commit ab2f6b3

Browse files
authored
Fail ignition build when the same jar in moduleContent folder with multiple versions detected (#68)
Fail the `zipModule` task when two or more jars in the `moduleContent` folder are the same dependency but at different versions. Overlapping jars can sneak into a build through transitive dependencies within the same build or bumping primary dependencies between builds without first `clean`ing.
1 parent 4fd236a commit ab2f6b3

File tree

3 files changed

+88
-2
lines changed

3 files changed

+88
-2
lines changed

gradle-module-plugin/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ repositories {
2020
}
2121

2222
group = "io.ia.sdk"
23-
version = "0.4.1"
23+
version = "0.5.0"
2424

2525
configurations {
2626
val functionalTestImplementation by registering {

gradle-module-plugin/src/functionalTest/kotlin/io/ia/sdk/gradle/modl/task/ZipModuleTests.kt

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,67 @@ package io.ia.sdk.gradle.modl.task
33
import io.ia.ignition.module.generator.ModuleGenerator
44
import io.ia.sdk.gradle.modl.BaseTest
55
import io.ia.sdk.gradle.modl.util.unsignedModuleName
6-
import org.junit.Test
6+
import org.gradle.api.Project
7+
import org.gradle.api.internal.project.DefaultProject
8+
import org.gradle.testfixtures.ProjectBuilder
9+
import java.io.File
10+
import kotlin.io.path.createTempDirectory
11+
import kotlin.test.AfterTest
12+
import kotlin.test.BeforeTest
13+
import kotlin.test.Test
14+
import kotlin.test.assertFailsWith
715
import kotlin.test.assertTrue
816

917
class ZipModuleTests : BaseTest() {
1018

19+
private lateinit var tempDir: File
20+
private lateinit var project: Project
21+
private lateinit var task: ZipModule
22+
23+
@BeforeTest
24+
fun setup() {
25+
tempDir = createTempDirectory().toFile()
26+
project = ProjectBuilder.builder().withProjectDir(tempDir).build() as DefaultProject
27+
task = project.tasks.create("testTask", ZipModule::class.java)
28+
29+
// Set up the task properties with the temp directory
30+
task.content.set(project.objects.directoryProperty().fileValue(File(tempDir, "content")))
31+
task.unsignedModule.set(project.objects.fileProperty().fileValue(File(tempDir, "output.modl")))
32+
}
33+
34+
@AfterTest
35+
fun cleanup() {
36+
tempDir.deleteRecursively()
37+
}
38+
39+
@Test
40+
fun `task succeeds when no duplicate jars exist`() {
41+
// Arrange
42+
val contentDir = task.content.asFile.get().apply { mkdirs() }
43+
File(contentDir, "my-lib-1.0.jar").createNewFile()
44+
File(contentDir, "another-lib-2.0.jar").createNewFile()
45+
46+
// Act: The task should not throw an exception
47+
task.execute()
48+
}
49+
50+
@Test
51+
fun `task fails when duplicate jars with different versions exist`() {
52+
// Arrange
53+
val contentDir = task.content.asFile.get().apply { mkdirs() }
54+
File(contentDir, "my-lib-1.0.jar").createNewFile()
55+
File(contentDir, "my-lib-2.0.jar").createNewFile() // This is the duplicate
56+
57+
// Act & Assert: The task should throw a IllegalArgumentException
58+
val exception = assertFailsWith<IllegalArgumentException> {
59+
task.execute()
60+
}
61+
62+
// Verify the exception message
63+
val expectedMessage = "Library 'my-lib' exists in multiple versions"
64+
assertTrue(exception.message!!.contains(expectedMessage))
65+
}
66+
1167
@Test
1268
fun `unsigned module is built and has appropriate name`() {
1369
val name = "Some Thing"

gradle-module-plugin/src/main/kotlin/io/ia/sdk/gradle/modl/task/ZipModule.kt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import org.gradle.api.tasks.OutputFile
1313
import org.gradle.api.tasks.PathSensitive
1414
import org.gradle.api.tasks.PathSensitivity
1515
import org.gradle.api.tasks.TaskAction
16+
import java.io.File
1617
import javax.inject.Inject
1718

1819
/**
@@ -46,10 +47,39 @@ open class ZipModule @Inject constructor(objects: ObjectFactory) : DefaultTask()
4647
val unsignedFile = unsignedModule.get()
4748
val contentDir = content.get().asFile
4849

50+
checkDuplicateJars(contentDir)
51+
4952
project.logger.info("Zipping '${contentDir.absolutePath}' into ' ${unsignedFile.asFile.absolutePath}'")
5053
project.ant.invokeMethod(
5154
"zip",
5255
mapOf("basedir" to contentDir, "destfile" to unsignedFile)
5356
)
5457
}
58+
59+
/**
60+
* Fail the build when jars in the contentDir with the same name has
61+
* multiple versions detected.
62+
**/
63+
fun checkDuplicateJars(contentDir: File) {
64+
project.logger.info("Parsing file name in: ${contentDir.absolutePath}")
65+
66+
val fileSet = mutableSetOf<String>()
67+
val regex = "^(.+?)-(?:\\d+.*)(?:\\.jar)".toRegex()
68+
69+
contentDir.walk().filter { it.isFile }.forEach { file ->
70+
val matchResult = regex.find(file.name) // Match all the jar files
71+
72+
if (matchResult != null) {
73+
val name = matchResult.groupValues[1]
74+
75+
if (fileSet.contains(name)) {
76+
throw IllegalArgumentException(
77+
"Library '$name' exists in multiple versions in ${contentDir.absolutePath}"
78+
)
79+
} else {
80+
fileSet.add(name)
81+
}
82+
}
83+
}
84+
}
5585
}

0 commit comments

Comments
 (0)