From 824b9a9672060774c1124aecb50ee580dc445e23 Mon Sep 17 00:00:00 2001 From: Sergey Patrikeev Date: Tue, 5 Feb 2019 20:04:28 +0300 Subject: [PATCH] MissingRecentAPI inspection: provide a setting to specify actual [since; until] compatibility range. --- .../missingApi/BuildNumberField.kt | 18 ++++++ .../missingApi/BuildNumberValueEditor.kt | 26 ++++++++ .../missingApi/MissingRecentApiInspection.kt | 63 +++++++++++++++++-- 3 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 plugins/devkit/devkit-core/src/inspections/missingApi/BuildNumberField.kt create mode 100644 plugins/devkit/devkit-core/src/inspections/missingApi/BuildNumberValueEditor.kt diff --git a/plugins/devkit/devkit-core/src/inspections/missingApi/BuildNumberField.kt b/plugins/devkit/devkit-core/src/inspections/missingApi/BuildNumberField.kt new file mode 100644 index 000000000000..f5ff14938910 --- /dev/null +++ b/plugins/devkit/devkit-core/src/inspections/missingApi/BuildNumberField.kt @@ -0,0 +1,18 @@ +// Copyright 2000-2019 JetBrains s.r.o. 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.inspections.missingApi + +import com.intellij.openapi.util.BuildNumber +import com.intellij.ui.components.JBTextField + +/** + * Text field used to input build numbers. + */ +class BuildNumberField(valueName: String, defaultValue: BuildNumber) : JBTextField() { + val valueEditor: BuildNumberValueEditor = BuildNumberValueEditor(this, valueName, defaultValue) + + var value: BuildNumber + get() = valueEditor.value + set(value) { + valueEditor.value = value + } +} \ No newline at end of file diff --git a/plugins/devkit/devkit-core/src/inspections/missingApi/BuildNumberValueEditor.kt b/plugins/devkit/devkit-core/src/inspections/missingApi/BuildNumberValueEditor.kt new file mode 100644 index 000000000000..75fcb681ece2 --- /dev/null +++ b/plugins/devkit/devkit-core/src/inspections/missingApi/BuildNumberValueEditor.kt @@ -0,0 +1,26 @@ +// Copyright 2000-2019 JetBrains s.r.o. 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.inspections.missingApi + +import com.intellij.openapi.util.BuildNumber +import com.intellij.openapi.util.InvalidDataException +import com.intellij.ui.components.fields.valueEditors.TextFieldValueEditor +import javax.swing.JTextField + +/** + * [TextFieldValueEditor] for [BuildNumber]s that can be used to validate user-inputed build numbers. + */ +class BuildNumberValueEditor(buildField: JTextField, valueName: String?, defaultValue: BuildNumber) + : TextFieldValueEditor(buildField, valueName, defaultValue) { + + override fun parseValue(text: String?): BuildNumber { + if (text.isNullOrBlank()) { + return defaultValue + } + return BuildNumber.fromStringOrNull(text) + ?: throw InvalidDataException("Invalid build number: $text") + } + + override fun valueToString(value: BuildNumber) = value.asString() + + override fun isValid(value: BuildNumber) = true +} diff --git a/plugins/devkit/devkit-core/src/inspections/missingApi/MissingRecentApiInspection.kt b/plugins/devkit/devkit-core/src/inspections/missingApi/MissingRecentApiInspection.kt index 54c1fe0661e6..e8d7952be0b0 100644 --- a/plugins/devkit/devkit-core/src/inspections/missingApi/MissingRecentApiInspection.kt +++ b/plugins/devkit/devkit-core/src/inspections/missingApi/MissingRecentApiInspection.kt @@ -10,10 +10,15 @@ import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.util.BuildNumber import com.intellij.psi.PsiElementVisitor import com.intellij.psi.xml.XmlFile +import com.intellij.ui.components.JBLabel +import com.intellij.util.ui.FormBuilder import org.jetbrains.idea.devkit.actions.DevkitActionsUtil import org.jetbrains.idea.devkit.module.PluginModuleType import org.jetbrains.idea.devkit.util.DescriptorUtil import org.jetbrains.idea.devkit.util.PsiUtil +import java.awt.BorderLayout +import javax.swing.JComponent +import javax.swing.JPanel /** * Inspection that warns plugin authors if they use IntelliJ Platform's APIs that aren't available @@ -36,6 +41,26 @@ class MissingRecentApiInspection : LocalInspectionTool() { val INSPECTION_SHORT_NAME = InspectionProfileEntry.getShortName(MissingRecentApiInspection::class.java.simpleName) } + /** + * Actual "since" build constraint of the plugin under development. + * + * Along with [untilBuildString] it may be set manually if values in plugin.xml + * differ from the actual values. For example, it is the case for gradle-intellij-plugin, + * which allows to override "since" and "until" values during plugin build. + */ + var sinceBuildString: String? = null + + /** + * Actual "until" build constraint of the plugin under development. + */ + var untilBuildString: String? = null + + private val sinceBuild: BuildNumber? + get() = sinceBuildString?.let { BuildNumber.fromStringOrNull(it) } + + private val untilBuild: BuildNumber? + get() = untilBuildString?.let { BuildNumber.fromStringOrNull(it) } + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { if (PsiUtil.isIdeaProject(holder.project)) { return PsiElementVisitor.EMPTY_VISITOR @@ -48,11 +73,41 @@ class MissingRecentApiInspection : LocalInspectionTool() { return MissingRecentApiVisitor(holder, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, targetedSinceUntilRanges) } + override fun createOptionsPanel(): JComponent { + val emptyBuildNumber = BuildNumber.fromString("1.0") + + val sinceField = BuildNumberField("since", emptyBuildNumber) + sinceBuild?.also { sinceField.value = it } + sinceField.emptyText.text = "the first IDE" + sinceField.valueEditor.addListener { value -> + sinceBuildString = value.takeIf { it != emptyBuildNumber }?.asString() + } + + val untilField = BuildNumberField("until", untilBuild ?: emptyBuildNumber) + untilField.emptyText.text = "all future IDEs" + untilBuild?.also { untilField.value = it } + untilField.valueEditor.addListener { value -> + untilBuildString = value.takeIf { it != emptyBuildNumber }?.asString() + } + + val formBuilder = FormBuilder.createFormBuilder() + .addComponent(JBLabel("Plugin compatibility range")) + .addLabeledComponent("since", sinceField) + .addLabeledComponent("until", untilField) + + val container = JPanel(BorderLayout()) + container.add(formBuilder.panel, BorderLayout.NORTH) + return container + } + private fun getTargetedSinceUntilRanges(module: Module): List { - return DevkitActionsUtil.getCandidatePluginModules(module) - .mapNotNull { PluginModuleType.getPluginXml(it) } - .mapNotNull { getSinceUntilRange(it) } - .filterNot { it.sinceBuild == null } + if (sinceBuild == null && untilBuild == null) { + return DevkitActionsUtil.getCandidatePluginModules(module) + .mapNotNull { PluginModuleType.getPluginXml(it) } + .mapNotNull { getSinceUntilRange(it) } + .filterNot { it.sinceBuild == null } + } + return listOf(SinceUntilRange(sinceBuild, untilBuild)) } private fun getSinceUntilRange(pluginXml: XmlFile): SinceUntilRange? {