Polishing Rewrite integration

This commit is contained in:
aboyko
2022-12-01 11:16:29 -05:00
parent 33904108c3
commit 88b591450a
13 changed files with 225 additions and 56 deletions

View File

@@ -196,7 +196,7 @@
category="org.springframework.tooling.boot.ls.preferences"
class="org.springframework.tooling.boot.ls.RewritePreferencePage"
id="org.springframework.tooling.boot.ls.rewrite"
name="Rewrite">
name="OpenRewrite">
</page>
<page
category="org.springframework.tooling.boot.ls.rewrite"
@@ -236,8 +236,12 @@
</activeWhen>
</handler>
<handler
class="org.springframework.tooling.boot.ls.commands.RewriteRefactoringsHandler"
commandId="org.springframework.tooling.boot.ls.Rewrite">
class="org.springframework.tooling.boot.ls.commands.RewriteRefactoringsHandler$RefactorBootProject"
commandId="org.springframework.tooling.boot.ls.rewrite.refactor">
</handler>
<handler
class="org.springframework.tooling.boot.ls.commands.RewriteRefactoringsHandler$UpgradeBootVersion"
commandId="org.springframework.tooling.boot.ls.rewrite.boot-upgrade">
</handler>
</extension>
<extension
@@ -256,8 +260,14 @@
<command
categoryId="org.springframework.ide.eclipse.commands"
description="Rewrite Refactorings for Spring Boot projects"
id="org.springframework.tooling.boot.ls.Rewrite"
name="Rewrite Refactorings...">
id="org.springframework.tooling.boot.ls.rewrite.refactor"
name="Refactor Spring Boot Project...">
</command>
<command
categoryId="org.springframework.ide.eclipse.commands"
description="Upgrade Spring Boot Version for a Spring Boot project"
id="org.springframework.tooling.boot.ls.rewrite.boot-upgrade"
name="Upgrade Spring Boot Version...">
</command>
</extension>
@@ -452,7 +462,7 @@
requiresUIAccess="false"/>
<computer
class="org.springframework.tooling.boot.ls.commands.RewriteCommandsQuickAccessProvider"
name="Spring - Rewrite Recipes">
name="Spring - OpenRewrite Recipes">
</computer>
</extension>
<extension
@@ -467,9 +477,9 @@
allPopups="false"
locationURI="popup:org.springframework.ide.eclipse.ui.tools?after=boot">
<command
commandId="org.springframework.tooling.boot.ls.Rewrite"
id="org.springframework.tooling.boot.ls.Rewrite"
label="Rewrite Refactorings..."
commandId="org.springframework.tooling.boot.ls.rewrite.boot-upgrade"
id="org.springframework.tooling.boot.ls.rewrite.boot-upgrade"
label="Upgrade Spring Boot Version..."
style="push">
<visibleWhen
checkEnabled="false">
@@ -522,6 +532,66 @@
</and>
</visibleWhen>
</command>
<command
commandId="org.springframework.tooling.boot.ls.rewrite.refactor"
id="org.springframework.tooling.boot.ls.rewrite.refactor"
label="Refactor Spring Boot Project..."
style="push">
<visibleWhen
checkEnabled="false">
<and>
<count
value="1">
</count>
<iterate>
<or>
<adapt
type="org.eclipse.core.resources.IResource">
<and>
<test
forcePluginActivation="true"
property="org.springsource.ide.eclipse.boot.isBootResource">
</test>
<or>
<test
property="org.eclipse.core.resources.name"
value="pom.xml">
</test>
<adapt
type="org.eclipse.core.resources.IProject">
<test
property="org.eclipse.core.resources.projectNature"
value="org.eclipse.m2e.core.maven2Nature">
</test>
</adapt>
</or>
</and>
</adapt>
<and>
<instanceof
value="org.eclipse.jdt.core.IJavaProject">
</instanceof>
<test
property="org.springsource.ide.eclipse.commons.java.projectNature"
value="org.eclipse.m2e.core.maven2Nature">
</test>
<test
forcePluginActivation="true"
property="org.springsource.ide.eclipse.boot.javaelement.isBootProject">
</test>
</and>
</or>
</iterate>
<test
property="org.springframework.tooling.boot.ls.areRewriteProjectRefactoringsOn">
</test>
</and>
</visibleWhen>
</command>
<separator
name="org.springframework.tooling.boot.ls.rewrite"
visible="true">
</separator>
</menuContribution>
</extension>
<extension

View File

@@ -31,7 +31,7 @@ public class RewritePreferencePage extends FieldEditorPreferencePage implements
"Project refactoring actions", fieldEditorParent));
addField(new BooleanFieldEditor(Constants.PREF_REWRITE_RECONCILE,
"Experimental reconciling for Java source based on Rewrite project", fieldEditorParent));
"Reconciling of Java Sources", fieldEditorParent));
}

View File

@@ -37,7 +37,7 @@ public class RewriteCommandsQuickAccessProvider implements IQuickAccessComputer,
@Override
public String getLabel() {
return "Reload Rewrite Recipes";
return "Reload OpenRewrite Recipes, Code Actions, Problem and Quick Fix Descriptors";
}
@Override
@@ -68,7 +68,7 @@ public class RewriteCommandsQuickAccessProvider implements IQuickAccessComputer,
ls.getWorkspaceService().executeCommand(commandParams)).toArray(CompletableFuture[]::new)).get(2, TimeUnit.SECONDS);
}
catch (Exception e) {
BootLanguageServerPlugin.getDefault().getLog().error("Failed to reload Rewrite Recipes!", e);
BootLanguageServerPlugin.getDefault().getLog().error("Failed to reload OpenRewrite Recipes!", e);
}
}
}

View File

@@ -53,6 +53,12 @@ import com.google.gson.JsonSerializer;
@SuppressWarnings("restriction")
public class RewriteRefactoringsHandler extends AbstractHandler {
public enum RecipeFilter {
ALL,
BOOT_UPGRADE,
NON_BOOT_UPGRADE
}
private static class DurationTypeConverter implements JsonSerializer<Duration>, JsonDeserializer<Duration> {
@Override
public JsonElement serialize(Duration src, Type srcType, JsonSerializationContext context) {
@@ -73,6 +79,16 @@ public class RewriteRefactoringsHandler extends AbstractHandler {
private static final String REWRITE_REFACTORINGS_LIST = "sts/rewrite/list";
private static final String REWRITE_REFACTORINGS_EXEC = "sts/rewrite/execute";
private RecipeFilter recipeFilter;
public RewriteRefactoringsHandler() {
this(RecipeFilter.ALL);
}
public RewriteRefactoringsHandler(RecipeFilter recipeFilter) {
this.recipeFilter = recipeFilter;
}
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
@@ -96,7 +112,7 @@ public class RewriteRefactoringsHandler extends AbstractHandler {
final String uri = project.getLocationURI().toString();
ExecuteCommandParams commandParams = new ExecuteCommandParams();
commandParams.setCommand(REWRITE_REFACTORINGS_LIST);
commandParams.setArguments(List.of(uri));
commandParams.setArguments(List.of(uri, recipeFilter.toString()));
try {
List<Object> allRewriteRecipesJson = new ArrayList<>();
@@ -152,5 +168,16 @@ public class RewriteRefactoringsHandler extends AbstractHandler {
}
return null;
}
public static class UpgradeBootVersion extends RewriteRefactoringsHandler {
public UpgradeBootVersion() {
super(RecipeFilter.BOOT_UPGRADE);
}
}
public static class RefactorBootProject extends RewriteRefactoringsHandler {
public RefactorBootProject() {
super(RecipeFilter.NON_BOOT_UPGRADE);
}
}
}

View File

@@ -29,6 +29,9 @@ public class StringListEditor extends ListEditor {
}
public static String[] decode(String value) {
if (value.isEmpty()) {
return new String[0];
}
return value.split(DELIMITER);
}

View File

@@ -31,6 +31,7 @@ import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -78,6 +79,26 @@ import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
public class RewriteRecipeRepository implements ApplicationContextAware {
enum RecipeFilter {
ALL,
BOOT_UPGRADE,
NON_BOOT_UPGRADE
}
private static final Pattern P1 = Pattern.compile("(Upgrade|Migrate)SpringBoot_\\d+_\\d+");
private static final Map<RecipeFilter, Predicate<Recipe>> RECIPE_LIST_FILTERS = new HashMap<>();
static {
RECIPE_LIST_FILTERS.put(RecipeFilter.ALL, r -> true);
RECIPE_LIST_FILTERS.put(RecipeFilter.BOOT_UPGRADE, r -> {
String n = lastTokenAfterDot(r.getName());
return P1.matcher(n).matches();
});
RECIPE_LIST_FILTERS.put(RecipeFilter.NON_BOOT_UPGRADE, r -> {
return RECIPE_LIST_FILTERS.get(RecipeFilter.BOOT_UPGRADE).negate().test(r);
});
}
private static final String CMD_REWRITE_RELOAD = "sts/rewrite/reload";
private static final String CMD_REWRITE_EXECUTE = "sts/rewrite/execute";
@@ -123,7 +144,7 @@ public class RewriteRecipeRepository implements ApplicationContextAware {
config.addListener(l -> {
Set<String> recipeFilterFromConfig = config.getRecipesFilters();
boolean firstTimeConfig = recipeFilters == UNINITIALIZED_SET && scanDirs == UNINITIALIZED_SET && scanFiles == UNINITIALIZED_SET;
if (recipeFilters == UNINITIALIZED_SET || recipeFilters.equals(recipeFilterFromConfig)) {
if (recipeFilters == UNINITIALIZED_SET || !recipeFilters.equals(recipeFilterFromConfig)) {
recipeFilters = recipeFilterFromConfig;
}
if (scanDirs == UNINITIALIZED_SET || !scanDirs.equals(config.getRecipeDirectories())
@@ -186,23 +207,27 @@ public class RewriteRecipeRepository implements ApplicationContextAware {
}
private boolean isAcceptableGlobalCommandRecipe(Recipe r) {
for (String filter : recipeFilters) {
if (!filter.isBlank()) {
// Check if wild-card character present
if (filter.indexOf('*') < 0) {
// No wild-card - direct equality
if (filter.equals(r.getName())) {
return isRecipeValid(r);
}
} else {
// Wild-card present - convert to regular expression
if (Pattern.matches(filter.replaceAll("\\*", "\\.*"), r.getName())) {
return isRecipeValid(r);
if (recipeFilters.isEmpty()) {
return isRecipeValid(r);
} else {
for (String filter : recipeFilters) {
if (!filter.isBlank()) {
// Check if wild-card character present
if (filter.indexOf('*') < 0) {
// No wild-card - direct equality
if (filter.equals(r.getName())) {
return isRecipeValid(r);
}
} else {
// Wild-card present - convert to regular expression
if (Pattern.matches(filter.replaceAll("\\*", "\\.*"), r.getName())) {
return isRecipeValid(r);
}
}
}
}
return false;
}
return false;
}
private static boolean isRecipeValid(Recipe r) {
@@ -298,11 +323,15 @@ public class RewriteRecipeRepository implements ApplicationContextAware {
private void registerCommands() {
server.onCommand(CMD_REWRITE_LIST, params -> {
JsonElement uri = (JsonElement) params.getArguments().get(0);
RecipeFilter f = params.getArguments().size() > 1 ? RecipeFilter.valueOf(((JsonElement) params.getArguments().get(1)).getAsString()) : RecipeFilter.ALL;
return loaded.thenApply(v -> {
if (uri == null) {
return Collections.emptyList();
} else {
return listProjectRefactoringRecipes(uri.getAsString()).stream().map(RewriteRecipeRepository::recipeToJson).collect(Collectors.toList());
return listProjectRefactoringRecipes(uri.getAsString()).stream()
.filter(RECIPE_LIST_FILTERS.get(f))
.map(RewriteRecipeRepository::recipeToJson)
.collect(Collectors.toList());
}
});
});
@@ -443,6 +472,14 @@ public class RewriteRecipeRepository implements ApplicationContextAware {
this.applicationContext = applicationContext;
}
private static String lastTokenAfterDot(String s) {
int idx = s.lastIndexOf('.');
if (idx >= 0 && idx < s.length() - 1) {
return s.substring(idx + 1);
}
return s;
}
// private static Recipe convert(Recipe r, RecipeDescriptor d) {
// try {
// if (d.selected) {

View File

@@ -87,7 +87,7 @@ public class AutowiredFieldIntoConstructorParameterCodeAction implements RecipeC
);
if (constructors.size() == 0) {
m = m.withMarkers(m.getMarkers().add(marker));
} else if (constructors.size() == 1 && !AutowiredFieldIntoConstructorParameterVisitor.isConstructorInitializingField(constructors.get(0), fieldName)) {
} else if (constructors.size() == 1 && AutowiredFieldIntoConstructorParameterVisitor.isNotConstructorInitializingField(constructors.get(0), fieldName)) {
m = m.withMarkers(m.getMarkers().add(marker));
} else {
List<MethodDeclaration> autowiredConstructors = constructors.stream().filter(constr -> constr.getLeadingAnnotations().stream()
@@ -98,7 +98,7 @@ public class AutowiredFieldIntoConstructorParameterCodeAction implements RecipeC
)
.limit(2)
.collect(Collectors.toList());
if (autowiredConstructors.size() == 1 && !AutowiredFieldIntoConstructorParameterVisitor.isConstructorInitializingField(autowiredConstructors.get(0), fieldName)) {
if (autowiredConstructors.size() == 1 && AutowiredFieldIntoConstructorParameterVisitor.isNotConstructorInitializingField(autowiredConstructors.get(0), fieldName)) {
m = m.withMarkers(m.getMarkers().add(marker));
}
}

View File

@@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.validation.generations;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.lsp4j.Diagnostic;
@@ -43,7 +44,8 @@ public class ProjectVersionDiagnosticProvider {
Version javaProjectVersion = SpringProjectUtil.getSpringBootVersion(javaProject);
if (javaProjectVersion == null) {
throw new Exception("Unable to resolve version for project: " + javaProject.getLocationUri().toString());
log.warn("Unable to resolve version for project: " + javaProject.getLocationUri().toString());
return new DiagnosticResult(buildFileUri, Collections.emptyList());
}
List<Diagnostic> diagnostics = new ArrayList<Diagnostic>();

View File

@@ -199,7 +199,7 @@ public class VersionValidators {
CodeAction ca = new CodeAction();
ca.setKind(CodeActionKind.QuickFix);
ca.setTitle("Upgrade to Version " + latest.toString());
ca.setTitle("Upgrade to Spring Boot " + latest.toString() + " (Maven dependency version changes only)");
String commandId = SpringBootUpgrade.CMD_UPGRADE_SPRING_BOOT;
ca.setCommand(new Command("Upgrade to Version " + latest.toString(), commandId,
ImmutableList.of(javaProject.getLocationUri().toString(), latest.toString())));
@@ -230,7 +230,7 @@ public class VersionValidators {
CodeAction ca = new CodeAction();
ca.setKind(CodeActionKind.QuickFix);
ca.setTitle("Upgrade to Version " + latest.toString());
ca.setTitle("Upgrade to Spring Boot " + latest.toString() + " (executes the full project conversion recipe from OpenRewrite)");
String commandId = SpringBootUpgrade.CMD_UPGRADE_SPRING_BOOT;
ca.setCommand(new Command("Upgrade to Version " + latest.toString(), commandId,
ImmutableList.of(javaProject.getLocationUri().toString(), latest.toString())));
@@ -261,7 +261,7 @@ public class VersionValidators {
CodeAction ca = new CodeAction();
ca.setKind(CodeActionKind.QuickFix);
ca.setTitle("Upgrade to Version " + latest.toString());
ca.setTitle("Upgrade to Spring Boot " + latest.toString() + " (executes the full project conversion recipe from OpenRewrite)");
String commandId = SpringBootUpgrade.CMD_UPGRADE_SPRING_BOOT;
ca.setCommand(new Command("Upgrade to Version " + latest.toString(), commandId,
ImmutableList.of(javaProject.getLocationUri().toString(), latest.toString())));

View File

@@ -12,6 +12,9 @@ package org.springframework.ide.vscode.boot.validation.generations.preferences;
import static org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity.HINT;
import static org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity.ERROR;
import static org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity.INFO;
import static org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity.WARNING;
import static org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity.IGNORE;
import org.springframework.ide.vscode.boot.common.SpringProblemCategories;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemCategory;
@@ -28,11 +31,11 @@ public enum VersionValidationProblemType implements ProblemType {
//
// SUPPORTED_COMMERCIAL_VERSION(HINT, "Supported Commercial Version", "Supported Commercial Version"),
UPDATE_LATEST_MAJOR_VERSION(HINT, "Update to Latest Major Version", "Update to Latest Major Version"),
UPDATE_LATEST_MAJOR_VERSION(IGNORE, "Update to Latest Major Version", "Update to Latest Major Version"),
UPDATE_LATEST_MINOR_VERSION(HINT, "Update to Latest Minor Version", "Update to Latest Minor Version"),
UPDATE_LATEST_MINOR_VERSION(INFO, "Update to Latest Minor Version", "Update to Latest Minor Version"),
UPDATE_LATEST_PATCH_VERSION(HINT, "Update to Latest Patch Version", "Update to Latest Patch Version");
UPDATE_LATEST_PATCH_VERSION(WARNING, "Update to Latest Patch Version", "Update to Latest Patch Version");
private final ProblemSeverity defaultSeverity;
private String description;

View File

@@ -307,19 +307,19 @@
"code": "UPDATE_LATEST_MAJOR_VERSION",
"label": "Update to Latest Major Version",
"description": "Update to Latest Major Version",
"defaultSeverity": "HINT"
"defaultSeverity": "IGNORE"
},
{
"code": "UPDATE_LATEST_MINOR_VERSION",
"label": "Update to Latest Minor Version",
"description": "Update to Latest Minor Version",
"defaultSeverity": "HINT"
"defaultSeverity": "INFO"
},
{
"code": "UPDATE_LATEST_PATCH_VERSION",
"label": "Update to Latest Patch Version",
"description": "Update to Latest Patch Version",
"defaultSeverity": "HINT"
"defaultSeverity": "WARNING"
}
]
}

View File

@@ -3,6 +3,9 @@ import { LanguageClient } from "vscode-languageclient/node";
import * as VSCode from 'vscode';
import * as path from "path";
const BOOT_UPGRADE = 'BOOT_UPGRADE';
const OTHER_REFACTORINGS = 'NON_BOOT_UPGRADE';
interface RecipeDescriptor {
name: string;
displayName: string;
@@ -85,11 +88,11 @@ const SUB_RECIPES_BUTTON: VSCode.QuickInputButton = {
tooltip: 'Sub-Recipes'
}
async function liveHoverConnectHandler(uri: VSCode.Uri) {
async function showRefactorings(uri: VSCode.Uri, filter: string) {
if (!uri) {
uri = await getTargetPomXml();
}
const choices = await showCurrentPathQuickPick(VSCode.commands.executeCommand('sts/rewrite/list', uri.toString(true)).then((cmds: RecipeDescriptor[]) => cmds.map(convertToQuickPickItem)), []);
const choices = await showCurrentPathQuickPick(VSCode.commands.executeCommand('sts/rewrite/list', uri.toString(true), filter).then((cmds: RecipeDescriptor[]) => cmds.map(convertToQuickPickItem)), []);
const recipeDescriptors = choices.filter(i => i.selected).map(convertToRecipeDescriptor);
if (recipeDescriptors.length) {
const aggregateRecipeDescriptor = recipeDescriptors.length === 1 ? recipeDescriptors[0] : {
@@ -214,9 +217,16 @@ export function activate(
context: VSCode.ExtensionContext
) {
context.subscriptions.push(
VSCode.commands.registerCommand('vscode-spring-boot.rewrite.list', params => {
VSCode.commands.registerCommand('vscode-spring-boot.rewrite.list.boot-upgrades', param => {
if (client.isRunning()) {
return liveHoverConnectHandler(params[0]);
return showRefactorings(param, BOOT_UPGRADE);
} else {
VSCode.window.showErrorMessage("No Spring Boot project found. Action is only available for Spring Boot Projects");
}
}),
VSCode.commands.registerCommand('vscode-spring-boot.rewrite.list.refactorings', param => {
if (client.isRunning()) {
return showRefactorings(param, OTHER_REFACTORINGS);
} else {
VSCode.window.showErrorMessage("No Spring Boot project found. Action is only available for Spring Boot Projects");
}

View File

@@ -32,7 +32,8 @@
"onLanguage:xml",
"onLanguage:spring-factories",
"onDebugResolve:java",
"onCommand:vscode-spring-boot.rewrite.list",
"onCommand:vscode-spring-boot.rewrite.list.refactorings",
"onCommand:vscode-spring-boot.rewrite.list.boot-upgrades",
"onCommand:vscode-spring-boot.ls.start",
"workspaceContains:pom.xml",
"workspaceContains:*/pom.xml",
@@ -94,14 +95,24 @@
"editor/context": [
{
"when": "resourceFilename == pom.xml",
"command": "vscode-spring-boot.rewrite.list",
"command": "vscode-spring-boot.rewrite.list.refactorings",
"group": "SpringBoot"
},
{
"when": "resourceFilename == pom.xml",
"command": "vscode-spring-boot.rewrite.list.boot-upgrades",
"group": "SpringBoot"
}
],
"explorer/context": [
{
"when": "resourceFilename == pom.xml && config.boot-java.rewrite.refactorings.on == true",
"command": "vscode-spring-boot.rewrite.list",
"command": "vscode-spring-boot.rewrite.list.refactorings",
"group": "SpringBoot"
},
{
"when": "resourceFilename == pom.xml && config.boot-java.rewrite.refactorings.on == true",
"command": "vscode-spring-boot.rewrite.list.boot-upgrades",
"group": "SpringBoot"
}
]
@@ -114,13 +125,19 @@
},
{
"enablement": "config.boot-java.rewrite.refactorings.on == true",
"command": "vscode-spring-boot.rewrite.list",
"command": "vscode-spring-boot.rewrite.list.boot-upgrades",
"category": "Spring Boot",
"title": "Rewrite Refactorings..."
"title": "Upgrade Spring Boot Version..."
},
{
"enablement": "config.boot-java.rewrite.refactorings.on == true",
"command": "vscode-spring-boot.rewrite.list.refactorings",
"category": "Spring Boot",
"title": "Refactor Spring Boot Project..."
},
{
"command": "vscode-spring-boot.rewrite.reload",
"title": "Reload Rewrite Recipes, Code Actions, Problem and Quick Fix Descriptors",
"title": "Reload OpenRewrite Recipes, Code Actions, Problem and Quick Fix Descriptors",
"category": "Spring Boot"
}
],
@@ -209,7 +226,7 @@
},
{
"id": "rewrite",
"title": "Rewrite",
"title": "OpenRewrite",
"order": 400,
"properties": {
"boot-java.rewrite.refactorings.on": {
@@ -220,7 +237,7 @@
"boot-java.rewrite.reconcile": {
"type": "boolean",
"default": false,
"description": "Experimental reconciling for Java source based on Rewrite project"
"description": "Reconciling Java Sources"
},
"boot-java.rewrite.recipe-filters": {
"type": "array",
@@ -816,7 +833,7 @@
},
"spring-boot.ls.problem.version-validation.UPDATE_LATEST_MAJOR_VERSION": {
"type": "string",
"default": "HINT",
"default": "IGNORE",
"description": "Update to Latest Major Version",
"enum": [
"IGNORE",
@@ -828,7 +845,7 @@
},
"spring-boot.ls.problem.version-validation.UPDATE_LATEST_MINOR_VERSION": {
"type": "string",
"default": "HINT",
"default": "INFO",
"description": "Update to Latest Minor Version",
"enum": [
"IGNORE",
@@ -840,7 +857,7 @@
},
"spring-boot.ls.problem.version-validation.UPDATE_LATEST_PATCH_VERSION": {
"type": "string",
"default": "HINT",
"default": "WARNING",
"description": "Update to Latest Patch Version",
"enum": [
"IGNORE",