Update Boot Version validation
Re-implemented boot version validation support using spring.io Generations
This commit is contained in:
@@ -23,17 +23,14 @@ import org.slf4j.LoggerFactory;
|
||||
public class SpringProjectUtil {
|
||||
|
||||
public static final String SPRING_BOOT = "spring-boot";
|
||||
|
||||
|
||||
// Pattern copied from https://semver.org/
|
||||
private static final String VERSION_PATTERN_STR = "(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:(-|\\.)((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?";
|
||||
private static final String GENERATION_VERSION_STR = "([0-9]+)";
|
||||
|
||||
public static final Logger log = LoggerFactory.getLogger(SpringProjectUtil.class);
|
||||
|
||||
private static final Pattern MAJOR_MINOR_VERSION = Pattern.compile("(0|[1-9]\\d*)\\.(0|[1-9]\\d*)");
|
||||
|
||||
// Pattern copied from https://semver.org/
|
||||
private static final Pattern VERSION = Pattern.compile(VERSION_PATTERN_STR);
|
||||
|
||||
private static final Pattern SPRING_NAME = Pattern.compile("([a-z]+)(-[a-z]+)*");
|
||||
private static final Pattern GENERATION_VERSION = Pattern.compile(GENERATION_VERSION_STR);
|
||||
|
||||
public static boolean isSpringProject(IJavaProject jp) {
|
||||
return hasSpecificLibraryOnClasspath(jp, "spring-core", true);
|
||||
@@ -46,40 +43,40 @@ public class SpringProjectUtil {
|
||||
public static boolean hasBootActuators(IJavaProject jp) {
|
||||
return hasSpecificLibraryOnClasspath(jp, "spring-boot-actuator-", true);
|
||||
}
|
||||
|
||||
public static String getMajMinVersion(String name) {
|
||||
Matcher matcher = MAJOR_MINOR_VERSION.matcher(name);
|
||||
if (matcher.find()) {
|
||||
int start = matcher.start();
|
||||
int end = matcher.end();
|
||||
return name.substring(start, end);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getVersion(String name) {
|
||||
Matcher matcher = VERSION.matcher(name);
|
||||
if (matcher.find()) {
|
||||
int start = matcher.start();
|
||||
int end = matcher.end();
|
||||
return name.substring(start, end);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param libName e.g. spring-boot-3.0.0.RELEASE.jar
|
||||
* @return "slug" portion: "spring-boot"
|
||||
* Parses version from the given generation name (e.g. "2.1.x"
|
||||
* @param name
|
||||
* @return Version if valid generation name with major and minor components
|
||||
* @throws Exception if invalid generation name
|
||||
*/
|
||||
public static String getProjectSlug(String libName) {
|
||||
Matcher matcher = SPRING_NAME.matcher(libName);
|
||||
public static Version getVersionFromGeneration(String name) throws Exception {
|
||||
Matcher matcher = GENERATION_VERSION.matcher(name);
|
||||
String major = null;
|
||||
String minor = null;
|
||||
|
||||
if (matcher.find()) {
|
||||
int start = matcher.start();
|
||||
int end = matcher.end();
|
||||
return libName.substring(start, end);
|
||||
major = name.substring(start, end);
|
||||
}
|
||||
return null;
|
||||
|
||||
if (matcher.find()) {
|
||||
int start = matcher.start();
|
||||
int end = matcher.end();
|
||||
minor = name.substring(start, end);
|
||||
}
|
||||
|
||||
if (major != null && minor != null) {
|
||||
return new Version(
|
||||
Integer.parseInt(major),
|
||||
Integer.parseInt(minor),
|
||||
0,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Invalid semver. Unable to parse major and minor version from: " + name);
|
||||
}
|
||||
|
||||
public static List<File> getLibrariesOnClasspath(IJavaProject jp, String libraryNamePrefix) {
|
||||
|
||||
@@ -63,9 +63,6 @@ import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexPro
|
||||
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndex;
|
||||
import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry;
|
||||
import org.springframework.ide.vscode.boot.properties.completions.SpringPropertiesCompletionEngine;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SampleProjectsProvider;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringIoProjectsProvider;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringProjectsValidations;
|
||||
import org.springframework.ide.vscode.boot.xml.SpringXMLCompletionEngine;
|
||||
import org.springframework.ide.vscode.boot.yaml.completions.ApplicationYamlAssistContext;
|
||||
import org.springframework.ide.vscode.boot.yaml.completions.SpringYamlCompletionEngine;
|
||||
@@ -93,7 +90,6 @@ import org.springframework.ide.vscode.languageserver.starter.LanguageServerRunne
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
@@ -291,13 +287,6 @@ public class BootLanguageServerBootApp {
|
||||
};
|
||||
}
|
||||
|
||||
@Bean SpringProjectsValidations springProjectsValidations(SimpleLanguageServer server) {
|
||||
return new SpringProjectsValidations(server, ImmutableList.of(
|
||||
new SpringIoProjectsProvider(),
|
||||
new SampleProjectsProvider()
|
||||
));
|
||||
}
|
||||
|
||||
@Bean FutureProjectFinder futureProjectFinder(JavaProjectFinder projectFinder, Optional<ProjectObserver> projectObserver) {
|
||||
return new FutureProjectFinder(projectFinder, projectObserver);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.lsp4j.MessageType;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -37,11 +36,8 @@ import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SymbolCache;
|
||||
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.boot.properties.BootPropertiesLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.ProjectValidation;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringProjectsValidations;
|
||||
import org.springframework.ide.vscode.boot.xml.SpringXMLLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.DiagnosticService;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.CompositeCompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
|
||||
@@ -51,7 +47,6 @@ import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFin
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.ShowMessageException;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
@@ -85,7 +80,6 @@ public class BootLanguageServerInitializer implements InitializingBean {
|
||||
@Autowired BootJavaConfig config;
|
||||
@Autowired SpringSymbolIndex springIndexer;
|
||||
@Autowired(required = false) List<ICompletionEngine> completionEngines;
|
||||
@Autowired SpringProjectsValidations springProjectsValidations;
|
||||
@Autowired private JavaProjectFinder projectFinder;
|
||||
@Autowired private LanguageServerProperties configProps;
|
||||
@Autowired(required = false) private RewriteRecipeRepository recipesRepo;
|
||||
@@ -180,9 +174,7 @@ public class BootLanguageServerInitializer implements InitializingBean {
|
||||
if (recipesRepo != null) {
|
||||
recipesRepo.onRecipesLoaded(v -> reconcile());
|
||||
}
|
||||
|
||||
addSpringProjectsVersionValidation(params);
|
||||
|
||||
|
||||
server.getWorkspaceService().getFileObserver().onFilesChanged(FILES_TO_WATCH_GLOB, this::handleFiles);
|
||||
server.getWorkspaceService().getFileObserver().onFilesCreated(FILES_TO_WATCH_GLOB, this::handleFiles);
|
||||
|
||||
@@ -210,51 +202,6 @@ public class BootLanguageServerInitializer implements InitializingBean {
|
||||
}
|
||||
}
|
||||
|
||||
private void addSpringProjectsVersionValidation(BootLanguageServerParams params2) {
|
||||
params.projectObserver.addListener(
|
||||
new ProjectObserver.Listener() {
|
||||
|
||||
@Override
|
||||
public void deleted(IJavaProject project) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void created(IJavaProject project) {
|
||||
|
||||
// TODO: PT 173730396 - As of 4.9.1, Spring Project Version validation is not yet
|
||||
// available from https://spring.io/api/projects
|
||||
// Commented out to disable this feature. Uncomment to test if necessary
|
||||
// validateProjectVersion(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changed(IJavaProject project) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
private void validateProjectVersion(IJavaProject project) {
|
||||
try {
|
||||
ProjectValidation validation = springProjectsValidations.validateVersion(project);
|
||||
if (validation != null && validation.getMessageType() == MessageType.Warning) {
|
||||
|
||||
// TODO: replace this with a diagnostic message that has project-scope.
|
||||
// At the moment of implementing this, it doesnt look like sending a diagnostic
|
||||
// message to LSP4E without a resource context is possible.
|
||||
DiagnosticService diagnosticService = server.getDiagnosticService();
|
||||
if (diagnosticService != null) {
|
||||
diagnosticService.diagnosticEvent(
|
||||
ShowMessageException.warning(validation.getMessage(), null));
|
||||
}
|
||||
log.warn(validation.getMessage());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed validating Spring Project version", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void validateProject(IJavaProject project, IReconcileEngine reconcileEngine) {
|
||||
if (configProps.isReconcileOnlyOpenedDocs()) {
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2022 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.app;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringBootProjectValidations;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringIoProjectsProvider;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringProjectDiagnostic;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringProjectsClient;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringProjectsProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class BootVersionValidator {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BootVersionValidator.class);
|
||||
|
||||
|
||||
public BootVersionValidator(SimpleLanguageServer server, ProjectObserver observer) {
|
||||
|
||||
observer.addListener(new ProjectObserver.Listener() {
|
||||
|
||||
@Override
|
||||
public void deleted(IJavaProject project) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void created(IJavaProject project) {
|
||||
|
||||
String url = "https://spring.io/api/projects";
|
||||
SpringProjectsClient client = new SpringProjectsClient(url);
|
||||
SpringProjectsProvider provider = new SpringIoProjectsProvider(client);
|
||||
|
||||
SpringBootProjectValidations validations = new SpringBootProjectValidations(provider);
|
||||
try {
|
||||
List<SpringProjectDiagnostic> diagnostics = validations.validateBootVersion(project);
|
||||
if (diagnostics != null) {
|
||||
for (SpringProjectDiagnostic springProjectDiagnostic : diagnostics) {
|
||||
server.getTextDocumentService().publishDiagnostics(new TextDocumentIdentifier(springProjectDiagnostic.getUri().toString()), List.of(springProjectDiagnostic.getDiagnostic()));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed validating Spring Project version", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changed(IJavaProject project) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2022 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.validation.generations;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.ide.vscode.boot.validation.generations.json.Generation;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.json.Generations;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.java.Version;
|
||||
|
||||
public abstract class BootDiagnosticProvider {
|
||||
|
||||
public static final String BOOT_VERSION_VALIDATION_CODE = "BOOT_VERSION_VALIDATION_CODE";;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param javaProject
|
||||
* @param info Spring Dependency Info
|
||||
* @param Spring project Generation information
|
||||
* @return Diagnostic if applicable to the given version, or null
|
||||
*/
|
||||
abstract SpringProjectDiagnostic getDiagnostic(IJavaProject javaProject, SpringDependencyInfo info, Generations generations) throws Exception;
|
||||
|
||||
protected URI getBuildFileUri(IJavaProject javaProject) throws Exception {
|
||||
// TODO: add gradle support here
|
||||
return getPomUri(javaProject);
|
||||
|
||||
}
|
||||
|
||||
private URI getPomUri(IJavaProject project) throws Exception {
|
||||
return new URI(project.getLocationUri().toString() + "/pom.xml");
|
||||
}
|
||||
|
||||
protected File getSpringBootDependency(IJavaProject project) {
|
||||
List<File> libs = SpringProjectUtil.getLibrariesOnClasspath(project, "spring-boot");
|
||||
return libs != null && libs.size() > 0 ? libs.get(0) : null;
|
||||
}
|
||||
|
||||
protected Version getVersion(Generation generation) throws Exception {
|
||||
return SpringProjectUtil.getVersionFromGeneration(generation.getName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.validation.generations;
|
||||
|
||||
import org.eclipse.lsp4j.MessageType;
|
||||
|
||||
public class ProjectValidation {
|
||||
|
||||
public static ProjectValidation OK = new ProjectValidation("", MessageType.Info);
|
||||
|
||||
private final MessageType messageType;
|
||||
private final String message;
|
||||
|
||||
public ProjectValidation(String message, MessageType messageType) {
|
||||
this.messageType = messageType;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
public MessageType getMessageType() {
|
||||
return messageType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2020, 2022 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.validation.generations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.ide.vscode.boot.validation.generations.json.Generations;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
|
||||
public class SpringBootProjectValidations {
|
||||
|
||||
private final SpringProjectsProvider projectsProvider;
|
||||
private static final String SPRING_BOOT_PROJECT_SLUG = "spring-boot";
|
||||
|
||||
private final BootDiagnosticProvider[] diagnosticProviders = new BootDiagnosticProvider[] {
|
||||
new UnsupportedVersionDiagnostic()
|
||||
};
|
||||
|
||||
public SpringBootProjectValidations(SpringProjectsProvider projectsProvider) {
|
||||
this.projectsProvider = projectsProvider;
|
||||
}
|
||||
|
||||
public List<SpringProjectDiagnostic> validateBootVersion(IJavaProject project) throws Exception {
|
||||
Builder<SpringProjectDiagnostic> builder = ImmutableList.builder();
|
||||
if (project != null) {
|
||||
SpringDependencyInfo info = new SpringDependencyInfo(project, SPRING_BOOT_PROJECT_SLUG);
|
||||
Generations generations = projectsProvider.getGenerations(SPRING_BOOT_PROJECT_SLUG);
|
||||
|
||||
for (BootDiagnosticProvider provider : diagnosticProviders) {
|
||||
SpringProjectDiagnostic diagnostic = provider.getDiagnostic(project, info, generations);
|
||||
if (diagnostic != null) {
|
||||
builder.add(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,10 +10,9 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.validation.generations;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.java.Version;
|
||||
|
||||
/**
|
||||
* Version info for a spring dependency.
|
||||
@@ -22,33 +21,25 @@ import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
* "spring-boot", the fullVersion "2.4.0-M4", and the majMin "2.4"
|
||||
*
|
||||
*/
|
||||
public class SpringVersionInfo {
|
||||
public class SpringDependencyInfo {
|
||||
|
||||
private final String slug;
|
||||
private final String majMin;
|
||||
private final String fullVersion;
|
||||
private final Version version;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param file spring for dependency, e.g. spring-boot-2.4.0-M4.jar
|
||||
*/
|
||||
public SpringVersionInfo(File file) {
|
||||
String fileName = FilenameUtils.getBaseName(file.getName());
|
||||
this.slug = SpringProjectUtil.getProjectSlug(fileName);
|
||||
this.majMin = SpringProjectUtil.getMajMinVersion(fileName);
|
||||
this.fullVersion = SpringProjectUtil.getVersion(fileName);
|
||||
public SpringDependencyInfo(IJavaProject project, String slug) {
|
||||
this.slug = slug;
|
||||
this.version = SpringProjectUtil.getDependencyVersion(project, slug);
|
||||
}
|
||||
|
||||
public String getSlug() {
|
||||
return slug;
|
||||
}
|
||||
|
||||
public String getMajMin() {
|
||||
return majMin;
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getFullVersion() {
|
||||
return fullVersion;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2022 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.validation.generations;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.lsp4j.Diagnostic;
|
||||
|
||||
public class SpringProjectDiagnostic {
|
||||
|
||||
private final Diagnostic diagnostic;
|
||||
private final URI uri;
|
||||
|
||||
public SpringProjectDiagnostic(Diagnostic diagnostic, URI uri) {
|
||||
this.diagnostic = diagnostic;
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public Diagnostic getDiagnostic() {
|
||||
return diagnostic;
|
||||
}
|
||||
|
||||
public URI getUri() {
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2020, 2021 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.validation.generations;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lsp4j.MessageType;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.json.Generation;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.json.Generations;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
|
||||
public class SpringProjectsValidations {
|
||||
|
||||
private final List<SpringProjectsProvider> projectsProviders;
|
||||
private final SimpleLanguageServer server;
|
||||
|
||||
public SpringProjectsValidations(SimpleLanguageServer server, List<SpringProjectsProvider> projectsProviders) {
|
||||
this.projectsProviders = projectsProviders;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public ProjectValidation validateVersion(IJavaProject jp) throws Exception {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (jp != null) {
|
||||
List<File> librariesOnClasspath = SpringProjectUtil.getLibrariesOnClasspath(jp, "spring");
|
||||
if (librariesOnClasspath != null) {
|
||||
for (File file : librariesOnClasspath) {
|
||||
SpringVersionInfo versionInfo = new SpringVersionInfo(file);
|
||||
for (SpringProjectsProvider projectsProvider : projectsProviders) {
|
||||
Generations generations = projectsProvider.getGenerations(versionInfo.getSlug());
|
||||
if (generations != null) {
|
||||
List<Generation> gens = generations.getGenerations();
|
||||
if (gens != null) {
|
||||
for (Generation gen : gens) {
|
||||
resolveWarnings(gen, builder, versionInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return builder.length() > 0 ?
|
||||
new ProjectValidation(builder.toString(), MessageType.Warning)
|
||||
: ProjectValidation.OK;
|
||||
}
|
||||
|
||||
private void resolveWarnings(Generation gen, StringBuilder messages, SpringVersionInfo versionInfo) {
|
||||
if (isInGeneration(versionInfo.getMajMin(), gen)) {
|
||||
Date currentDate = new Date(System.currentTimeMillis());
|
||||
Date ossEndDate = Date.valueOf(gen.getOssSupportEndDate());
|
||||
Date commercialEndDate = Date.valueOf(gen.getCommercialSupportEndDate());
|
||||
|
||||
messages.append("Using ");
|
||||
messages.append(versionInfo.getSlug());
|
||||
messages.append(" version: ");
|
||||
messages.append(versionInfo.getFullVersion());
|
||||
|
||||
if (currentDate.after(ossEndDate)) {
|
||||
messages.append(" - OSS has ended on: ");
|
||||
messages.append(gen.getOssSupportEndDate());
|
||||
}
|
||||
if (currentDate.after(commercialEndDate)) {
|
||||
messages.append(" - Commercial support has ended on: ");
|
||||
messages.append(gen.getCommercialSupportEndDate());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInGeneration(String version, Generation g) {
|
||||
return g.getName().contains(version);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2022 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.validation.generations;
|
||||
|
||||
import java.net.URI;
|
||||
import java.sql.Date;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lsp4j.CodeAction;
|
||||
import org.eclipse.lsp4j.CodeActionKind;
|
||||
import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.eclipse.lsp4j.DiagnosticSeverity;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.json.Generation;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.json.Generations;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.Version;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public class UnsupportedVersionDiagnostic extends BootDiagnosticProvider {
|
||||
|
||||
|
||||
@Override
|
||||
public SpringProjectDiagnostic getDiagnostic(IJavaProject project, SpringDependencyInfo dependency, Generations generations) throws Exception {
|
||||
|
||||
URI uri = getBuildFileUri(project);
|
||||
if (uri == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Generation> genList = generations.getGenerations();
|
||||
|
||||
// The generation of the current dependency
|
||||
Generation dependencyGeneration = null;
|
||||
|
||||
int dependencyMajor = dependency.getVersion().getMajor();
|
||||
int dependencyMinor = dependency.getVersion().getMinor();
|
||||
|
||||
// Collect the latest versions of each major version that are still supported
|
||||
List<Generation> latestSupportedPerMajor = new ArrayList<>();
|
||||
|
||||
if (genList != null && genList.size() > 1) {
|
||||
|
||||
// The very latest version is first in the list as the generations are ordered by version
|
||||
latestSupportedPerMajor.add(genList.get(0));
|
||||
|
||||
for (int i = 1; i < genList.size(); i++) {
|
||||
Generation toAdd = genList.get(i);
|
||||
Version toAddVersion = getVersion(toAdd);
|
||||
|
||||
Generation lastAdded = latestSupportedPerMajor.get(latestSupportedPerMajor.size() - 1);
|
||||
Version lastAddedVersion = getVersion(lastAdded);
|
||||
|
||||
if (isCommercialValid(toAdd) && isOssValid(toAdd) && toAddVersion.getMajor() < lastAddedVersion.getMajor()) {
|
||||
latestSupportedPerMajor.add(toAdd);
|
||||
}
|
||||
if (toAddVersion.getMajor() == dependencyMajor
|
||||
&& toAddVersion.getMinor() == dependencyMinor) {
|
||||
dependencyGeneration = toAdd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dependencyGeneration == null) {
|
||||
throw new Exception("Unable to find Spring Generation for: " + dependency.getVersion().toString());
|
||||
}
|
||||
|
||||
StringBuffer message = new StringBuffer();
|
||||
DiagnosticSeverity severity = DiagnosticSeverity.Information;
|
||||
|
||||
if (isCommercialValid(dependencyGeneration) && isOssValid(dependencyGeneration)) {
|
||||
message.append("OSS support ends on: ");
|
||||
message.append(dependencyGeneration.getOssSupportEndDate());
|
||||
message.append('\n');
|
||||
message.append("Commercial supports ends on: ");
|
||||
message.append(dependencyGeneration.getCommercialSupportEndDate());
|
||||
} else {
|
||||
|
||||
Generation toUpgrade = null;
|
||||
|
||||
// Calculate latest supported version for the same major version as the dependency
|
||||
// For example, if the dependency version is 1.5.0 and the latest supported is 1.8.0,
|
||||
// find the generation for 1.8.0
|
||||
for (Generation generation : latestSupportedPerMajor) {
|
||||
Version dependencyVersion = getVersion(dependencyGeneration);
|
||||
Version latest = getVersion(generation);
|
||||
if (latest.getMajor() == dependencyVersion.getMajor()) {
|
||||
toUpgrade = generation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (toUpgrade == null) {
|
||||
// if there are no supported versions in the dependency major range, upgrade to the very
|
||||
// latest version
|
||||
toUpgrade = latestSupportedPerMajor.get(0);
|
||||
}
|
||||
|
||||
if (isCommercialValid(dependencyGeneration)) {
|
||||
severity = DiagnosticSeverity.Warning;
|
||||
message.append("Unsupported OSS. Support ended on: ");
|
||||
message.append(dependencyGeneration.getOssSupportEndDate());
|
||||
message.append('\n');
|
||||
message.append("Commercial supports ends on: ");
|
||||
message.append(dependencyGeneration.getCommercialSupportEndDate());
|
||||
|
||||
} else if (isOssValid(dependencyGeneration)) {
|
||||
severity = DiagnosticSeverity.Warning;
|
||||
message.append("OSS support ends on: ");
|
||||
message.append(dependencyGeneration.getOssSupportEndDate());
|
||||
message.append('\n');
|
||||
message.append("Unsupported Commercial. Support ended on: ");
|
||||
message.append(dependencyGeneration.getCommercialSupportEndDate());
|
||||
|
||||
} else {
|
||||
// OSS and Commercial support have ended
|
||||
severity = DiagnosticSeverity.Error;
|
||||
|
||||
message.append("Unsupported OSS. Support ended on: ");
|
||||
message.append(dependencyGeneration.getOssSupportEndDate());
|
||||
message.append('\n');
|
||||
message.append("Unsupported Commercial. Support ended on: ");
|
||||
message.append(dependencyGeneration.getCommercialSupportEndDate());
|
||||
}
|
||||
|
||||
message.append('\n');
|
||||
message.append("Please upgrade to a newer supported version: ");
|
||||
message.append(getVersion(toUpgrade).toString());
|
||||
}
|
||||
|
||||
Diagnostic diagnostic = new Diagnostic();
|
||||
diagnostic.setCode(BOOT_VERSION_VALIDATION_CODE);
|
||||
diagnostic.setMessage(message.toString());
|
||||
|
||||
Range range = new Range();
|
||||
Position start = new Position();
|
||||
start.setLine(0);
|
||||
start.setCharacter(0);
|
||||
range.setStart(start);
|
||||
Position end = new Position();
|
||||
end.setLine(0);
|
||||
end.setCharacter(1);
|
||||
range.setEnd(end);
|
||||
diagnostic.setRange(range);
|
||||
diagnostic.setSeverity(severity);
|
||||
|
||||
|
||||
setQuickfix(diagnostic);
|
||||
|
||||
return new SpringProjectDiagnostic(diagnostic, uri);
|
||||
}
|
||||
|
||||
|
||||
private void setQuickfix(Diagnostic diagnostic) {
|
||||
// TODO: Fix this when open rewrite recipe quickfix becomes available.
|
||||
Diagnostic refDiagnostic = new Diagnostic(diagnostic.getRange(), diagnostic.getMessage(), diagnostic.getSeverity(), diagnostic.getSource());
|
||||
CodeAction ca = new CodeAction();
|
||||
ca.setKind(CodeActionKind.QuickFix);
|
||||
ca.setTitle("Validation FIX");
|
||||
ca.setDiagnostics(List.of(refDiagnostic));
|
||||
String commandId = "";
|
||||
ca.setCommand(new Command("Validation FIX", commandId, ImmutableList.of()));
|
||||
diagnostic.setData(ca);
|
||||
}
|
||||
|
||||
|
||||
private boolean isOssValid(Generation gen) {
|
||||
|
||||
Date currentDate = new Date(System.currentTimeMillis());
|
||||
Date ossEndDate = Date.valueOf(gen.getOssSupportEndDate());
|
||||
return currentDate.before(ossEndDate);
|
||||
}
|
||||
|
||||
private boolean isCommercialValid(Generation gen) {
|
||||
|
||||
Date currentDate = new Date(System.currentTimeMillis());
|
||||
Date commercialEndDate = Date.valueOf(gen.getCommercialSupportEndDate());
|
||||
|
||||
return currentDate.before(commercialEndDate);
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lsp4j.MessageType;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -26,25 +24,20 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
|
||||
import org.springframework.ide.vscode.boot.bootiful.HoverTestConf;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.ProjectValidation;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SampleProjectsProvider;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringIoProjectsProvider;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringProjectsClient;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringProjectsProvider;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.SpringProjectsValidations;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.json.Generation;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.json.Generations;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.json.Link;
|
||||
import org.springframework.ide.vscode.boot.validation.generations.json.SpringProject;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.java.Version;
|
||||
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@BootLanguageServerTest
|
||||
@Import(HoverTestConf.class)
|
||||
@@ -61,89 +54,6 @@ public class ProjectGenerationsValidationTest {
|
||||
harness.intialize(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMajMinVersionParsing() throws Exception {
|
||||
String version = SpringProjectUtil.getMajMinVersion("spring-boot-starter-batch-2.3.4.RELEASE");
|
||||
assertEquals("2.3", version);
|
||||
|
||||
version = SpringProjectUtil.getMajMinVersion("spring-batch-core-2.4.0-M4");
|
||||
assertEquals("2.4", version);
|
||||
|
||||
version = SpringProjectUtil.getMajMinVersion("spring-boot-4.4.0-RC2");
|
||||
assertEquals("4.4", version);
|
||||
|
||||
version = SpringProjectUtil.getMajMinVersion("spring-integration-70.811.0.RELEASE");
|
||||
assertEquals("70.811", version);
|
||||
|
||||
version = SpringProjectUtil.getMajMinVersion("another-java-");
|
||||
assertNull(version);
|
||||
|
||||
version = SpringProjectUtil.getMajMinVersion("spring-core-5.f.2");
|
||||
assertNull(version);
|
||||
|
||||
version = SpringProjectUtil.getMajMinVersion("springcore.f.b");
|
||||
assertNull(version);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersionParsing() throws Exception {
|
||||
String version = SpringProjectUtil.getVersion("spring-boot-starter-batch-2.3.0.RELEASE");
|
||||
assertEquals("2.3.0.RELEASE", version);
|
||||
|
||||
version = SpringProjectUtil.getVersion("spring-batch-core-2.4.0-M4");
|
||||
assertEquals("2.4.0-M4", version);
|
||||
|
||||
version = SpringProjectUtil.getVersion("spring-batch-core-2.4.0");
|
||||
assertEquals("2.4.0", version);
|
||||
|
||||
version = SpringProjectUtil.getVersion("spring-boot-4.4.0-RC2");
|
||||
assertEquals("4.4.0-RC2", version);
|
||||
|
||||
version = SpringProjectUtil.getVersion("spring-integration-70.811.0.RELEASE");
|
||||
assertEquals("70.811.0.RELEASE", version);
|
||||
|
||||
version = SpringProjectUtil.getVersion("another-java-");
|
||||
assertNull(version);
|
||||
|
||||
version = SpringProjectUtil.getVersion("spring-core-5.f.2");
|
||||
assertNull(version);
|
||||
|
||||
version = SpringProjectUtil.getVersion("springcore.f.b");
|
||||
assertNull(version);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProjectSlugParsing() throws Exception {
|
||||
String slug = SpringProjectUtil.getProjectSlug("spring-batch-core-2.4.0-M4");
|
||||
assertEquals("spring-batch-core", slug);
|
||||
|
||||
slug = SpringProjectUtil.getProjectSlug("spring-2.4.0-M4");
|
||||
assertEquals("spring", slug);
|
||||
|
||||
slug = SpringProjectUtil.getProjectSlug("-4.4.0-RC2");
|
||||
assertNull(slug);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersionAndLibsFromActualProject() throws Exception {
|
||||
IJavaProject jp = projects.mavenProject("empty-boot-1.3.0-app");
|
||||
assertTrue(SpringProjectUtil.isBootProject(jp));
|
||||
|
||||
List<File> springLibs = SpringProjectUtil.getLibrariesOnClasspath(jp, "spring");
|
||||
assertNotNull(springLibs);
|
||||
assertTrue(springLibs.size() > 1);
|
||||
|
||||
File file = getLib(springLibs, "spring-boot");
|
||||
assertNotNull(file);
|
||||
assertTrue(file.exists());
|
||||
|
||||
String version = SpringProjectUtil.getMajMinVersion(file.getName());
|
||||
assertEquals("1.3", version);
|
||||
|
||||
String slug = SpringProjectUtil.getProjectSlug(file.getName());
|
||||
assertEquals("spring-boot", slug);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProjectsInfoFromSpringIo() throws Exception {
|
||||
@@ -195,22 +105,6 @@ public class ProjectGenerationsValidationTest {
|
||||
assertEquals("2021-01-01", generation.getCommercialSupportEndDate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWarningsFromSample() throws Exception {
|
||||
|
||||
IJavaProject jp = projects.mavenProject("empty-boot-1.3.0-app");
|
||||
|
||||
SpringProjectsValidations validation = new SpringProjectsValidations(harness.getServer(),
|
||||
ImmutableList.of( new SampleProjectsProvider())
|
||||
);
|
||||
|
||||
ProjectValidation versionValidation = validation.validateVersion(jp);
|
||||
assertNotNull(versionValidation != null);
|
||||
assertEquals(versionValidation.getMessageType(), MessageType.Warning);
|
||||
// Check that the message mentions the boot version of the project and the OSS support end date
|
||||
assertEquals("Using spring-boot version: 1.3.2.RELEASE - OSS has ended on: 2020-01-01 - Commercial support has ended on: 2021-01-01", versionValidation.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDependencyVersionCalculation() throws Exception {
|
||||
Version version = SpringProjectUtil.getDependencyVersion("spring-boot-1.2.3.jar", "spring-boot");
|
||||
@@ -240,26 +134,4 @@ public class ProjectGenerationsValidationTest {
|
||||
version = SpringProjectUtil.getDependencyVersion("spring-boot-actuator-1.2.3.BUILD-SNAPSHOT.jar", "spring-boot");
|
||||
assertNull(version);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* Helper methods
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
private File getLib(List<File> springLibs, String slug) {
|
||||
for (File file : springLibs) {
|
||||
String name = file.getName();
|
||||
String libSlug = SpringProjectUtil.getProjectSlug(name);
|
||||
if (slug.equals(libSlug)) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user