diff --git a/plugins/devkit/devkit-core/intellij.devkit.iml b/plugins/devkit/devkit-core/intellij.devkit.iml
index 2de433272b5d..a2961da857dd 100644
--- a/plugins/devkit/devkit-core/intellij.devkit.iml
+++ b/plugins/devkit/devkit-core/intellij.devkit.iml
@@ -6,6 +6,7 @@
+
@@ -63,5 +64,6 @@
+
\ No newline at end of file
diff --git a/plugins/devkit/devkit-core/src/commit/KotlinPluginCommitMessageHandlerFactory.kt b/plugins/devkit/devkit-core/src/commit/KotlinPluginCommitMessageHandlerFactory.kt
index 20ba6012b89b..7d9a2ede1e8a 100644
--- a/plugins/devkit/devkit-core/src/commit/KotlinPluginCommitMessageHandlerFactory.kt
+++ b/plugins/devkit/devkit-core/src/commit/KotlinPluginCommitMessageHandlerFactory.kt
@@ -13,26 +13,36 @@ import com.intellij.util.PairConsumer
import com.intellij.util.io.systemIndependentPath
import org.jetbrains.idea.devkit.DevKitBundle
import org.jetbrains.idea.devkit.util.PsiUtil
+import java.io.File
import kotlin.io.path.extension
-import kotlin.io.path.isRegularFile
class KotlinPluginCommitMessageHandlerFactory : CheckinHandlerFactory() {
- companion object {
- private const val kotlinPluginPath = "plugins/kotlin/"
- private val pathsToIgnore = setOf("/test/", "/testData/")
- private val fileExtensionsNotToTrack = setOf("iml", "md")
- private val commitMessageRegex = Regex(".*KTIJ-\\d+.*", RegexOption.DOT_MATCHES_ALL /* line breaks matter */)
- }
-
override fun createHandler(panel: CheckinProjectPanel, commitContext: CommitContext): CheckinHandler =
YouTrackIssueCommitMessageHandler(panel)
- private class YouTrackIssueCommitMessageHandler(private val checkinPanel: CheckinProjectPanel) : CheckinHandler() {
+ internal class YouTrackIssueCommitMessageHandler(private val checkinPanel: CheckinProjectPanel) : CheckinHandler() {
companion object {
- const val HANDLER_ENABLED_KEY = "kotlin.commit.message.validation.enabled"
+ private const val HANDLER_ENABLED_KEY = "kotlin.commit.message.validation.enabled"
+ private const val KOTLIN_PLUGIN_PATH = "plugins/kotlin/"
+ private val pathsToIgnore = setOf("/test/", "/testData/", "/fleet/plugins/kotlin/")
+ private val fileExtensionsNotToTrack = setOf("iml", "md")
+ private val commitMessageRegex = Regex(".*KTIJ-\\d+.*", RegexOption.DOT_MATCHES_ALL /* line breaks matter */)
+
+ internal fun selectedFilesBelongToKotlinIdePlugin(files: Collection): Boolean {
+ return files.asSequence()
+ .map { file -> file.toPath() }
+ .any { path ->
+ val siPath = path.systemIndependentPath
+ path.extension !in fileExtensionsNotToTrack
+ && siPath.contains(KOTLIN_PLUGIN_PATH)
+ && pathsToIgnore.none { siPath.contains(it) }
+ }
+ }
+
+ internal fun commitMessageIsCorrect(message: String): Boolean = message.matches(commitMessageRegex)
}
private val project = checkinPanel.project
@@ -52,7 +62,7 @@ class KotlinPluginCommitMessageHandlerFactory : CheckinHandlerFactory() {
if (!messageHandlerEnabled
|| !commitMessageShouldBeChecked()
- || checkinPanel.commitMessage.matches(commitMessageRegex)
+ || commitMessageIsCorrect(checkinPanel.commitMessage)
) {
return ReturnResult.COMMIT // as is
}
@@ -73,18 +83,6 @@ class KotlinPluginCommitMessageHandlerFactory : CheckinHandlerFactory() {
}
private fun commitMessageShouldBeChecked(): Boolean =
- PsiUtil.isIdeaProject(project) && selectedFilesBelongToKotlinIdePlugin()
-
- private fun selectedFilesBelongToKotlinIdePlugin(): Boolean {
- return checkinPanel.files.asSequence()
- .map { file -> file.toPath() }
- .any { path ->
- val siPath = path.systemIndependentPath
- path.isRegularFile()
- && path.extension !in fileExtensionsNotToTrack
- && siPath.contains(kotlinPluginPath)
- && pathsToIgnore.none { siPath.contains(it) }
- }
- }
+ PsiUtil.isIdeaProject(project) && selectedFilesBelongToKotlinIdePlugin(checkinPanel.files)
}
}
\ No newline at end of file
diff --git a/plugins/devkit/devkit-core/testSrc/org/jetbrains/idea/devkit/commit/KotlinYouTrackIssueCommitMessageHandlerTest.kt b/plugins/devkit/devkit-core/testSrc/org/jetbrains/idea/devkit/commit/KotlinYouTrackIssueCommitMessageHandlerTest.kt
new file mode 100644
index 000000000000..aa214e49eb24
--- /dev/null
+++ b/plugins/devkit/devkit-core/testSrc/org/jetbrains/idea/devkit/commit/KotlinYouTrackIssueCommitMessageHandlerTest.kt
@@ -0,0 +1,276 @@
+// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package org.jetbrains.idea.devkit.commit
+
+import org.jetbrains.idea.devkit.commit.KotlinPluginCommitMessageHandlerFactory.YouTrackIssueCommitMessageHandler
+import org.junit.Test
+import org.junit.experimental.runners.Enclosed
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameter
+import java.io.File
+import java.nio.file.Paths
+
+@RunWith(Enclosed::class)
+class KotlinYouTrackIssueCommitMessageHandlerTest {
+
+ @RunWith(Parameterized::class)
+ class FilesBelongToPlugin {
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun provideTestParameters(): Iterable>> {
+ return listOf(
+ listOf(ULTIMATE_KOTLIN_PLUGIN to "File.kt"),
+ listOf(COMMUNITY_KOTLIN_PLUGIN to "File.kt"),
+
+ listOf(ULTIMATE_KOTLIN_PLUGIN to "File.kts"),
+ listOf(COMMUNITY_KOTLIN_PLUGIN to "File.kts"),
+
+ listOf(ULTIMATE_KOTLIN_PLUGIN to "File.java"),
+ listOf(COMMUNITY_KOTLIN_PLUGIN to "File.java"),
+
+ listOf(ULTIMATE_KOTLIN_PLUGIN to "File.properties"),
+ listOf(COMMUNITY_KOTLIN_PLUGIN to "File.properties"),
+
+ listOf(ULTIMATE_KOTLIN_PLUGIN to "File.html"),
+ listOf(COMMUNITY_KOTLIN_PLUGIN to "File.html"),
+
+ listOf(ULTIMATE_KOTLIN_PLUGIN to "File.xml"),
+ listOf(COMMUNITY_KOTLIN_PLUGIN to "File.xml"),
+
+ listOf(
+ COMMUNITY_KOTLIN_PLUGIN to "File.kt",
+ "not-important-dir-A" to "whatever-file",
+ "not-important-dir-B" to "whatever-file"
+ ),
+
+ listOf(
+ "not-important-dir-A" to "whatever-file",
+ COMMUNITY_KOTLIN_PLUGIN to "File.kt",
+ "not-important-dir-B" to "whatever-file"
+ ),
+
+ listOf(
+ "not-important-dir-A" to "whatever-file",
+ "not-important-dir-B" to "whatever-file",
+ COMMUNITY_KOTLIN_PLUGIN to "File.kt"
+ )
+ )
+ }
+ }
+
+ @Parameter
+ lateinit var files: List>
+
+ @Test
+ fun testThatChecksForFileSet() {
+ val filesSet = files.map { fileAt(it.first, it.second) }
+ assert(YouTrackIssueCommitMessageHandler.selectedFilesBelongToKotlinIdePlugin(filesSet)) {
+ "The following set of files doesn't trigger the check: $filesSet"
+ }
+ }
+ }
+
+
+ @RunWith(Parameterized::class)
+ class FilesDoNotBelongToPlugin {
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun provideTestParameters(): Iterable>> {
+ return listOf(
+ // file path has no kotlin-plugin subdirectory
+ listOf("not-important-dir" to "File.kt"),
+ listOf(FLEET_KOTLIN_PLUGIN to "File.kt"),
+
+ // kotlin-plugin path contains subdirectories to exclude
+ listOf("$ULTIMATE_KOTLIN_PLUGIN/test/" to "File.kt"),
+ listOf("$ULTIMATE_KOTLIN_PLUGIN/testData/" to "File.kt"),
+
+ // file extensions to exclude
+ listOf(COMMUNITY_KOTLIN_PLUGIN to "File.iml"),
+ listOf(COMMUNITY_KOTLIN_PLUGIN to "File.md"),
+
+ // multiple files, none matches
+ listOf(
+ "not-important-dir" to "File.kt",
+ FLEET_KOTLIN_PLUGIN to "File.kt",
+ "$ULTIMATE_KOTLIN_PLUGIN/test/" to "File.kt",
+ "$ULTIMATE_KOTLIN_PLUGIN/testData/" to "File.kt",
+ COMMUNITY_KOTLIN_PLUGIN to "File.iml",
+ COMMUNITY_KOTLIN_PLUGIN to "File.md"
+ )
+ )
+ }
+ }
+
+ @Parameter
+ lateinit var files: List>
+
+ @Test
+ fun testThatIgnoresFileSet() {
+ val filesSet = files.map { fileAt(it.first, it.second) }
+ assert(!YouTrackIssueCommitMessageHandler.selectedFilesBelongToKotlinIdePlugin(filesSet)) {
+ "The following set of files triggered the check: $filesSet"
+ }
+ }
+ }
+
+ @RunWith(Parameterized::class)
+ class ValidCommitMessages {
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun provideTestParameters(): Iterable {
+ return listOf(
+ "KTIJ-123",
+ "(KTIJ-123)",
+ "[KTIJ-123]",
+ "{KTIJ-123}",
+ "'KTIJ-123'",
+ "`KTIJ-123`",
+ "\"KTIJ-123\"",
+
+ "KTIJ-123 ",
+ " KTIJ-123",
+ " KTIJ-123 ",
+
+ "KTIJ-123 header",
+ "Header KTIJ-123",
+ "Header KTIJ-123 header",
+
+ """
+ Header KTIJ-123 header
+
+ Body-line-1
+ Body-line-N
+ """.trimIndent(),
+
+ """
+ Header KTIJ-123 header
+
+ Body-line-1
+ Body-line-N
+
+ ^KTIJ-123 fixed
+ """.trimIndent(),
+
+ """
+ Header
+
+ Body-line-1
+ Body-line-N
+
+ ^KTIJ-123 fixed
+ """.trimIndent(),
+
+ """
+ Header
+
+ Body-line-1
+ Body-line-N
+
+ #KTIJ-123 fixed
+ """.trimIndent(),
+
+ """
+ Header
+
+ Body-line-1
+ Body-line-N
+
+ Relates to #KTIJ-123
+ """.trimIndent()
+ )
+ }
+ }
+
+ @Parameter
+ lateinit var commitMessage: String
+
+ @Test
+ fun testThatCommitMessageIsValid() {
+ assert(YouTrackIssueCommitMessageHandler.commitMessageIsCorrect(commitMessage)) {
+ "The following commit message was considered invalid: $commitMessage"
+ }
+ }
+ }
+
+ @RunWith(Parameterized::class)
+ class InvalidCommitMessages {
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun provideTestParameters(): Iterable {
+ return listOf(
+ "",
+ "KTIJ",
+ "KTIJ-",
+ "KTIJ-one",
+ "KT-123",
+ "IDEA-123",
+ "WHATEVER-123",
+ "Header KTIJ",
+ "Header KTIJ header",
+
+ """
+ Header
+
+ Body-line-1
+ Body-line-N
+ """.trimIndent(),
+
+ """
+ Header
+
+ Body-line-1
+ Body-line-N
+
+ ^IDEA-123 fixed
+ """.trimIndent(),
+
+ """
+ Header
+
+ Body-line-1
+ Body-line-N
+
+ #IDEA-123 fixed
+ """.trimIndent(),
+
+ """
+ Header
+
+ Body-line-1
+ Body-line-N
+
+ Relates to #IDEA-123
+ """.trimIndent(),
+ )
+ }
+ }
+
+ @Parameter
+ lateinit var commitMessage: String
+
+ @Test
+ fun testThatCommitMessageIsValid() {
+ assert(!YouTrackIssueCommitMessageHandler.commitMessageIsCorrect(commitMessage)) {
+ "The following commit message was considered as valid: $commitMessage"
+ }
+ }
+ }
+}
+
+
+val tempDir: String = System.getProperty("java.io.tmpdir")
+const val ULTIMATE_KOTLIN_PLUGIN = "plugins/kotlin/package/"
+const val COMMUNITY_KOTLIN_PLUGIN = "community/plugins/kotlin/package/"
+const val FLEET_KOTLIN_PLUGIN = "fleet/plugins/kotlin/package/"
+
+
+private fun fileAt(dirPath: String, fileName: String): File {
+ return Paths.get(tempDir, *dirPath.split("/").toTypedArray(), fileName).toFile()
+}
\ No newline at end of file