diff --git a/application/src/main/kotlin/application/BackwardCompatibilityCheckCommand.kt b/application/src/main/kotlin/application/BackwardCompatibilityCheckCommand.kt index 5d194a570..09724908c 100644 --- a/application/src/main/kotlin/application/BackwardCompatibilityCheckCommand.kt +++ b/application/src/main/kotlin/application/BackwardCompatibilityCheckCommand.kt @@ -11,10 +11,12 @@ import java.io.File import java.util.concurrent.Callable @Component -@Command(name = "backwardCompatibilityCheck", - mixinStandardHelpOptions = true, - description = ["Checks backward compatibility of a directory across the current HEAD and the main branch"]) -class BackwardCompatibilityCheckCommand( +@Command( + name = "backwardCompatibilityCheck", + mixinStandardHelpOptions = true, + description = ["Checks backward compatibility of a directory across the current HEAD and the main branch"] +) +open class BackwardCompatibilityCheckCommand( private val gitCommand: GitCommand, ) : Callable { @@ -29,7 +31,7 @@ class BackwardCompatibilityCheckCommand( override fun call() { val filesChangedInCurrentBranch: Set = getOpenAPISpecFilesChangedInCurrentBranch() - if(filesChangedInCurrentBranch.isEmpty()) exitWithMessage("$newLine OpenAPI spec files were changed, skipping the check.$newLine") + if (filesChangedInCurrentBranch.isEmpty()) exitWithMessage("$newLine OpenAPI spec files were changed, skipping the check.$newLine") val filesReferringToChangedSchemaFiles = filesReferringToChangedSchemaFiles(filesChangedInCurrentBranch) @@ -42,7 +44,7 @@ class BackwardCompatibilityCheckCommand( val result = runBackwardCompatibilityCheckFor(filesToCheck) - if(result == FAILED) { + if (result == FAILED) { exitWithMessage("$newLine Verdict: FAIL, backward incompatible changes were found.") } println("$newLine Verdict: PASS, all changes were backward compatible") @@ -50,7 +52,7 @@ class BackwardCompatibilityCheckCommand( private fun runBackwardCompatibilityCheckFor(files: Set): String { val currentBranch = gitCommand.currentBranch() - val currentTreeish = if(currentBranch == HEAD) gitCommand.detachedHEAD() else currentBranch + val currentTreeish = if (currentBranch == HEAD) gitCommand.detachedHEAD() else currentBranch try { val failures = files.mapIndexed { index, specFilePath -> @@ -74,7 +76,11 @@ class BackwardCompatibilityCheckCommand( SUCCESS } else { println("$newLine ${backwardCompatibilityResult.report().prependIndent(MARGIN_SPACE)}") - println("$newLine *** The file $specFilePath is NOT backward compatible. ***$newLine".prependIndent(MARGIN_SPACE)) + println( + "$newLine *** The file $specFilePath is NOT backward compatible. ***$newLine".prependIndent( + MARGIN_SPACE + ) + ) FAILED } }.filter { it == FAILED } @@ -85,7 +91,10 @@ class BackwardCompatibilityCheckCommand( } } - private fun logFilesToBeCheckedForBackwardCompatibility(changedFiles : Set, filesReferringToChangedFiles: Set) { + private fun logFilesToBeCheckedForBackwardCompatibility( + changedFiles: Set, + filesReferringToChangedFiles: Set + ) { println("Checking backward compatibility of the following files: $newLine") println("Files that have changed - ") changedFiles.forEach { println(it) } @@ -98,18 +107,22 @@ class BackwardCompatibilityCheckCommand( println() } - private fun filesReferringToChangedSchemaFiles(schemaFiles : Set): Set { - if(schemaFiles.isEmpty()) return emptySet() + internal fun filesReferringToChangedSchemaFiles(schemaFiles: Set): Set { + if (schemaFiles.isEmpty()) return emptySet() val schemaFileBaseNames = schemaFiles.map { File(it).name } - return allOpenApiSpecFiles().filter { + val result = allOpenApiSpecFiles().filter { it.readText().let { specContent -> schemaFileBaseNames.any { schemaFileBaseName -> schemaFileBaseName in specContent } } }.map { it.path }.toSet() + + return result.flatMap { + filesReferringToChangedSchemaFiles(setOf(it)).ifEmpty { setOf(it) } + }.toSet() } - private fun allOpenApiSpecFiles(): List { + internal fun allOpenApiSpecFiles(): List { return File(".").walk().toList().filterNot { ".git" in it.path }.filter { it.isFile && it.isOpenApiSpec() } @@ -117,12 +130,12 @@ class BackwardCompatibilityCheckCommand( private fun getOpenAPISpecFilesChangedInCurrentBranch(): Set { return gitCommand.getFilesChangeInCurrentBranch().filter { - File(it).exists() && File(it).isOpenApiSpec() + File(it).exists() && File(it).isOpenApiSpec() }.toSet() } private fun File.isOpenApiSpec(): Boolean { - if(this.extension !in CONTRACT_EXTENSIONS) return false + if (this.extension !in CONTRACT_EXTENSIONS) return false return OpenApiSpecification.isParsable(this.path) } } diff --git a/application/src/test/kotlin/application/BackwardCompatibilityCheckCommandTest.kt b/application/src/test/kotlin/application/BackwardCompatibilityCheckCommandTest.kt new file mode 100644 index 000000000..5b34ecc3c --- /dev/null +++ b/application/src/test/kotlin/application/BackwardCompatibilityCheckCommandTest.kt @@ -0,0 +1,39 @@ +package application + +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test +import java.io.File + +class BackwardCompatibilityCheckCommandTest { + + @Test + fun `filesReferringToChangedSchemaFiles returns empty set when input is empty`() { + val command = BackwardCompatibilityCheckCommand(mockk()) + val result = command.filesReferringToChangedSchemaFiles(emptySet()) + assertTrue(result.isEmpty()) + } + + @Test + fun `filesReferringToChangedSchemaFiles returns empty set when no files refer to changed schema files`() { + val command = BackwardCompatibilityCheckCommand(mockk(relaxed = true)) + every { command.allOpenApiSpecFiles() } returns listOf( + File("file1.yaml").apply { writeText("content1") }, + File("file2.yaml").apply { writeText("content2") } + ) + val result = command.filesReferringToChangedSchemaFiles(setOf("file3.yaml")) + assertTrue(result.isEmpty()) + } + + @Test + fun `filesReferringToChangedSchemaFiles returns set of files that refer to changed schema files`() { + val command = mockk(relaxed = true) + every { command.allOpenApiSpecFiles() } returns listOf( + File("file1.yaml").apply { writeText("file3.yaml") }, + File("file2.yaml").apply { writeText("file4.yaml") } + ) + val result = command.filesReferringToChangedSchemaFiles(setOf("file3.yaml")) + assertEquals(setOf("file1.yaml"), result) + } +} \ No newline at end of file