[Kotlin] YT-issue commit handler

We at Kotlin-IDE team decided to introduce subtle changes in our
development practices. One of them deals with commits messages.
We strive to transparency and want to keep our QA aware of
changes we make. Practically it means referring to YT-issues
in all meaningful commits.

GitOrigin-RevId: 63c82c3806c17a8131d1b2d32d9c9b7740027200
This commit is contained in:
Andrei Klunnyi
2021-11-30 17:31:45 +01:00
committed by intellij-monorepo-bot
parent 8c51467b94
commit 2af7a5c8d6
5 changed files with 113 additions and 3 deletions

View File

@@ -25,6 +25,7 @@
<resource-bundle>messages.DevKitBundle</resource-bundle>
<extensions defaultExtensionNs="com.intellij">
<checkinHandlerFactory implementation="org.jetbrains.idea.devkit.commit.KotlinPluginCommitMessageHandlerFactory"/>
<virtualFileSystem key="testdata" implementationClass="org.jetbrains.idea.devkit.testAssistant.vfs.TestDataGroupFileSystem"/>
<editorTabTitleProvider implementation="org.jetbrains.idea.devkit.testAssistant.TestDataGroupEditorTabTitleProvider"/>
<highlightingPassFactory implementation="org.jetbrains.idea.devkit.testAssistant.TestDataHighlightingPassFactory"/>
@@ -407,6 +408,8 @@
<registryKey key="tmh.generate.line.numbers" defaultValue="true"
description="Generate line numbers when instrumenting @RequiresEdt and similar annotations.
This results in better stack traces when generated assertions throw exceptions, but might slow down the compilation."/>
<registryKey key="kotlin.commit.message.validation.enabled" defaultValue="true"
description="Enables commit messages validation for kotlin plugin"/>
</extensions>
<extensions defaultExtensionNs="JavaScript.JsonSchema">
<ProviderFactory implementation="org.jetbrains.idea.devkit.themes.ThemeJsonSchemaProviderFactory"/>

View File

@@ -1,3 +1,13 @@
commit.message.lacks.issue.reference.body=\
<html>The commit changes the Kotlin IDE plugin sources. \
According to the <a href=https://github.com/JetBrains/intellij-community/blob/master/plugins/kotlin/README.md#2-commits-requirements>rules</a> \
of the plugin team, all meaningful commits should reference a <a href=https://youtrack.jetbrains.com/newIssue?project=KTIJ>KTIJ</a>\
\ issue in their message. \
Do you still want to commit as is?</html>
commit.message.lacks.issue.reference.title=Message Lacks YouTrack Issue Reference
commit.message.lacks.issue.reference.commit=Commit As Is
commit.message.lacks.issue.reference.edit=Edit Message
#module type
module.title=IntelliJ Platform Plugin
module.description=Plugin modules are used for developing plugins for <b>IntelliJ Platform</b>-based IDEs.<br>\

View File

@@ -0,0 +1,90 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.devkit.commit
import com.intellij.openapi.ui.MessageDialogBuilder
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vcs.CheckinProjectPanel
import com.intellij.openapi.vcs.changes.CommitContext
import com.intellij.openapi.vcs.changes.CommitExecutor
import com.intellij.openapi.vcs.checkin.CheckinHandler
import com.intellij.openapi.vcs.checkin.CheckinHandlerFactory
import com.intellij.openapi.vcs.ui.RefreshableOnComponent
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 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+.*")
}
override fun createHandler(panel: CheckinProjectPanel, commitContext: CommitContext): CheckinHandler =
YouTrackIssueCommitMessageHandler(panel)
private class YouTrackIssueCommitMessageHandler(private val checkinPanel: CheckinProjectPanel) : CheckinHandler() {
companion object {
const val HANDLER_ENABLED_KEY = "kotlin.commit.message.validation.enabled"
}
private val project = checkinPanel.project
// IMPORTANT!!! Method is called only once in case of non-modal commit window.
// Literally, we cannot give the user smart-appearing check-box "Check my message".
// Other than that we cannot track files selection. If relevant file gets selected we won't react.
override fun getBeforeCheckinConfigurationPanel(): RefreshableOnComponent? = null
// IMPORTANT: called independently of getBeforeCheckinConfigurationPanel() result, i.e. always
override fun beforeCheckin(
executor: CommitExecutor?,
additionalDataConsumer: PairConsumer<Any, Any>?
): ReturnResult {
val messageHandlerEnabled = Registry.`is`(HANDLER_ENABLED_KEY, true)
if (!messageHandlerEnabled
|| !commitMessageShouldBeChecked()
|| checkinPanel.commitMessage.matches(commitMessageRegex)
) {
return ReturnResult.COMMIT // as is
}
val commitAsIs = MessageDialogBuilder.yesNo(
DevKitBundle.message("commit.message.lacks.issue.reference.title"),
DevKitBundle.message("commit.message.lacks.issue.reference.body")
)
.yesText(DevKitBundle.message("commit.message.lacks.issue.reference.commit"))
.noText(DevKitBundle.message("commit.message.lacks.issue.reference.edit"))
.asWarning()
.ask(project)
if (commitAsIs)
return ReturnResult.COMMIT
return ReturnResult.CANCEL
}
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) }
}
}
}
}

View File

@@ -51,8 +51,9 @@ to the "up-for-grabs" tag is a safe way to go.
We have several requirements for the Pull Requests:
1. A Pull Request must solve some issue. So the issue identifier must be specified.
We use [KT](https://youtrack.jetbrains.com/issues/KT) and [KTIJ](https://youtrack.jetbrains.com/issues/KTIJ) projects on YouTrack.
If the issue doesn't exist yet, please create it in [KTIJ](https://youtrack.jetbrains.com/issues/KTIJ).
We use [KTIJ](https://youtrack.jetbrains.com/issues/KTIJ) project on YouTrack.
If the issue doesn't exist yet, please [create it](https://youtrack.jetbrains.com/newIssue?project=KTIJ).
<br/> We also kindly ask you to follow "Commits Requirements" described in [README](README.md).
2. Do not submit Pull Requests that solve multiple issues that aren't interconnected. Create several PRs instead.
3. The plugin must still work after the change. Please ensure the plugin compiles and runs successfully after the change.
4. Each non-trivial change in plugin functionality must come with tests, so add new tests or adapt existing ones.

View File

@@ -36,7 +36,13 @@ Now you should be able to open and build the project.
Use the provided `IDEA` build configuration to run an IntelliJ IDEA instance with your modifications to the Kotlin plugin.
## 2. Frequently Asked Questions
## 2. Commits Requirements
We strive for transparency of changes. Therefore, all meaningful commits should reference a
[KTIJ](https://youtrack.jetbrains.com/issues/KTIJ) issue in their message.
It is permissible not to follow this rule if a change relates to tests, it is a minor refactoring or code formatting.
## 3. Frequently Asked Questions
Q. How can I contribute to the Kotlin IDEA plugin?
A. We accept Pull Requests. Please read our [contribution guide](CONTRIBUTING.md) for more information.