Spring IO Generations API validation

This commit is contained in:
aboyko
2023-02-07 19:08:08 -05:00
parent 3a337427ac
commit 42e714faad
11 changed files with 227 additions and 218 deletions

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2022 Pivotal, Inc.
* Copyright (c) 2017, 2023 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
@@ -36,6 +36,8 @@ import org.springframework.stereotype.Component;
@Component
public class BootJavaConfig implements InitializingBean {
private static final String SPRING_IO_API_URL = "https://api.spring.io/projects";
private static final Logger log = LoggerFactory.getLogger(BootJavaConfig.class);
public static final boolean LIVE_INFORMATION_AUTOMATIC_TRACKING_ENABLED_DEFAULT = false;
@@ -152,6 +154,11 @@ public class BootJavaConfig implements InitializingBean {
Boolean enabled = getRawSettings().getBoolean("boot-java", "rewrite", "reconcile");
return enabled == null ? false : enabled.booleanValue();
}
public String getSpringIOApiUrl() {
String url = getRawSettings().getString("spring-boot", "io", "api");
return url == null ? SPRING_IO_API_URL : url;
}
public boolean isXmlContentAssistEnabled() {

View File

@@ -22,6 +22,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.ide.vscode.boot.common.ProjectReconcileScheduler;
import org.springframework.ide.vscode.boot.java.rewrite.SpringBootUpgrade;
import org.springframework.ide.vscode.boot.validation.BootVersionValidationEngine;
import org.springframework.ide.vscode.boot.validation.generations.GenerationsValidator;
import org.springframework.ide.vscode.boot.validation.generations.ProjectVersionDiagnosticProvider;
import org.springframework.ide.vscode.boot.validation.generations.UpdateBootVersion;
import org.springframework.ide.vscode.boot.validation.generations.VersionValidator;
@@ -39,6 +40,10 @@ public class BootVersionValidationConfig {
return new UpdateBootVersion(server.getDiagnosticSeverityProvider(), bootUpgradeOpt);
}
@Bean GenerationsValidator generationsValidator(SimpleLanguageServer server, BootJavaConfig config) {
return new GenerationsValidator(server.getDiagnosticSeverityProvider(), config);
}
@Bean ProjectVersionDiagnosticProvider projectVersionDiagnosticProvider(List<VersionValidator> validators) {
return new ProjectVersionDiagnosticProvider(validators);
}

View File

@@ -0,0 +1,109 @@
/*******************************************************************************
* Copyright (c) 2023 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.Collection;
import java.util.List;
import org.eclipse.lsp4j.Diagnostic;
import org.springframework.ide.vscode.boot.app.BootJavaConfig;
import org.springframework.ide.vscode.boot.validation.generations.json.Generation;
import org.springframework.ide.vscode.boot.validation.generations.json.ResolvedSpringProject;
import org.springframework.ide.vscode.boot.validation.generations.preferences.VersionValidationProblemType;
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.commons.languageserver.reconcile.DiagnosticSeverityProvider;
import org.springframework.ide.vscode.commons.util.Assert;
import com.google.common.collect.ImmutableList;
public class GenerationsValidator extends AbstractDiagnosticValidator {
private SpringIoProjectsProvider provider;
public GenerationsValidator(DiagnosticSeverityProvider diagnosticSeverityProvider, BootJavaConfig config) {
super(diagnosticSeverityProvider);
provider = new SpringIoProjectsProvider(config.getSpringIOApiUrl());
config.addListener(v -> provider.updateIoApiUri(config.getSpringIOApiUrl()));
}
private static Generation getGenerationForJavaProject(IJavaProject javaProject, ResolvedSpringProject springProject)
throws Exception {
List<Generation> genList = springProject.getGenerations();
Version javaProjectVersion = SpringProjectUtil.getDependencyVersion(javaProject, springProject.getSlug());
// Find the generation belonging to the dependency
for (Generation gen : genList) {
Version genVersion = SpringProjectUtil.getVersionFromGeneration(gen.getName());
if (genVersion.getMajor() == javaProjectVersion.getMajor()
&& genVersion.getMinor() == javaProjectVersion.getMinor()) {
return gen;
}
}
return null;
}
@Override
public Collection<Diagnostic> validate(IJavaProject javaProject, Version javaProjectVersion) throws Exception {
ResolvedSpringProject springProject = provider.getProject(SpringProjectUtil.SPRING_BOOT);
Generation javaProjectGen = getGenerationForJavaProject(javaProject, springProject);
Assert.isLegal(javaProjectGen != null, "Unable to find Spring Project Generation for project: " + javaProjectVersion.toString());
ImmutableList.Builder<Diagnostic> b = ImmutableList.builder();
if (VersionValidationUtils.isOssValid(javaProjectGen)) {
StringBuilder message = new StringBuilder();
message.append("OSS support for Spring Boot ");
message.append(javaProjectGen.getName());
message.append(" ends on: ");
message.append(javaProjectGen.getOssSupportEndDate());
Diagnostic d = createDiagnostic(VersionValidationProblemType.SUPPORTED_OSS_VERSION, message.toString());
if (d != null) {
b.add(d);
}
} else {
StringBuilder message = new StringBuilder();
message.append("OSS support for Spring Boot ");
message.append(javaProjectGen.getName());
message.append(" no longer available, ended on: ");
message.append(javaProjectGen.getOssSupportEndDate());
Diagnostic d = createDiagnostic(VersionValidationProblemType.UNSUPPORTED_OSS_VERSION, message.toString());
if (d != null) {
b.add(d);
}
}
if (VersionValidationUtils.isCommercialValid(javaProjectGen)) {
StringBuilder message = new StringBuilder();
message.append("Commercial support for Spring Boot ");
message.append(javaProjectGen.getName());
message.append(" ends on: ");
message.append(javaProjectGen.getCommercialSupportEndDate());
Diagnostic d = createDiagnostic(VersionValidationProblemType.SUPPORTED_COMMERCIAL_VERSION, message.toString());
if (d != null) {
b.add(d);
}
} else {
StringBuilder message = new StringBuilder();
message.append("Commercial support for Spring Boot ");
message.append(javaProjectGen.getName());
message.append(" no longer available, ended on: ");
message.append(javaProjectGen.getCommercialSupportEndDate());
Diagnostic d = createDiagnostic(VersionValidationProblemType.UNSUPPORTED_COMMERCIAL_VERSION, message.toString());
if (d != null) {
b.add(d);
}
}
return b.build();
}
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2020 Pivotal, Inc.
* Copyright (c) 2020, 2023 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
@@ -30,11 +30,17 @@ import com.google.common.collect.ImmutableMap.Builder;
*/
public class SpringIoProjectsProvider implements SpringProjectsProvider {
private final SpringProjectsClient client;
private SpringProjectsClient client;
private Map<String, ResolvedSpringProject> cache;
public SpringIoProjectsProvider(SpringProjectsClient client) {
this.client = client;
public SpringIoProjectsProvider(String uri) {
updateIoApiUri(uri);
}
public synchronized void updateIoApiUri(String uri) {
if (client == null || !uri.equals(client.getUrl())) {
this.client = new SpringProjectsClient(uri);
}
}
/**
@@ -44,7 +50,7 @@ public class SpringIoProjectsProvider implements SpringProjectsProvider {
* @throws Exception
*/
@Override
public ResolvedSpringProject getProject(String projectSlug) throws Exception {
public synchronized ResolvedSpringProject getProject(String projectSlug) throws Exception {
ResolvedSpringProject prj = cache().get(projectSlug);
return prj;
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2020 Pivotal, Inc.
* Copyright (c) 2020, 2023 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
@@ -32,6 +32,10 @@ public class SpringProjectsClient {
this.url = url;
}
public String getUrl() {
return url;
}
public SpringProjects getSpringProjects() throws Exception {
return fromEmbedded(url, SpringProjects.class);
}

View File

@@ -1,171 +0,0 @@
/*******************************************************************************
* Copyright (c) 2022, 2023 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.Arrays;
import java.util.List;
import org.springframework.ide.vscode.commons.languageserver.reconcile.DiagnosticSeverityProvider;
/*
* TODO: Once uncommented to bring in Spring.io generations API support:
* 1. Remaining validators must become beans.
* 2. I'd merge all 4 into one single validator
*/
public class VersionValidators {
private final VersionValidator[] validators;
public VersionValidators(DiagnosticSeverityProvider diagnosticSeverityProvider, SpringProjectsProvider provider) {
this.validators = new VersionValidator[] {
// new SupportedOssValidator(diagnosticSeverityProvider, provider),
// new UnsupportedCommercialValidator(diagnosticSeverityProvider, provider),
// new UnsupportedOssValidator(diagnosticSeverityProvider, provider),
// new SupportedCommercialValidator(diagnosticSeverityProvider, provider),
};
}
public List<VersionValidator> getValidators() {
return Arrays.asList(this.validators);
}
// private static Generation getGenerationForJavaProject(IJavaProject javaProject, ResolvedSpringProject springProject)
// throws Exception {
// List<Generation> genList = springProject.getGenerations();
// Version javaProjectVersion = SpringProjectUtil.getDependencyVersion(javaProject, springProject.getSlug());
//
// // Find the generation belonging to the dependency
// for (Generation gen : genList) {
// Version genVersion = SpringProjectUtil.getVersionFromGeneration(gen.getName());
// if (genVersion.getMajor() == javaProjectVersion.getMajor()
// && genVersion.getMinor() == javaProjectVersion.getMinor()) {
// return gen;
// }
// }
// return null;
// }
//
// private static class SupportedOssValidator extends AbstractDiagnosticValidator {
//
// private SpringProjectsProvider provider;
//
// public SupportedOssValidator(DiagnosticSeverityProvider diagnosticSeverityProvider, SpringProjectsProvider provider) {
// super(diagnosticSeverityProvider);
// this.provider = provider;
// }
//
// @Override
// public Diagnostic validate(IJavaProject javaProject, Version javaProjectVersion) throws Exception {
// ResolvedSpringProject springProject = provider.getProject(SpringProjectUtil.SPRING_BOOT);
// Generation javaProjectGen = getGenerationForJavaProject(javaProject, springProject);
// Assert.isLegal(javaProjectGen != null, "Unable to find Spring Project Generation for project: " + javaProjectVersion.toString());
// if (VersionValidationUtils.isOssValid(javaProjectGen)) {
// VersionValidationProblemType problemType = VersionValidationProblemType.SUPPORTED_OSS_VERSION;
//
// StringBuffer message = new StringBuffer();
// message.append("OSS support for Spring Boot " + javaProjectGen.getName() + " ends on: ");
// message.append(javaProjectGen.getOssSupportEndDate());
//
// return createDiagnostic(problemType, message.toString());
// }
// return null;
// }
// }
//
// private static class SupportedCommercialValidator extends AbstractDiagnosticValidator {
//
// private SpringProjectsProvider provider;
//
// public SupportedCommercialValidator(DiagnosticSeverityProvider diagnosticSeverityProvider, SpringProjectsProvider provider) {
// super(diagnosticSeverityProvider);
// this.provider = provider;
// }
//
// @Override
// public Diagnostic validate(IJavaProject javaProject, Version javaProjectVersion) throws Exception {
// ResolvedSpringProject springProject = provider.getProject(SpringProjectUtil.SPRING_BOOT);
// Generation javaProjectGen = getGenerationForJavaProject(javaProject, springProject);
// Assert.isLegal(javaProjectGen != null, "Unable to find Spring Project Generation for project: " + javaProjectVersion.toString());
//
// if (VersionValidationUtils.isCommercialValid(javaProjectGen)) {
//
// VersionValidationProblemType problemType = VersionValidationProblemType.SUPPORTED_COMMERCIAL_VERSION;
//
// StringBuffer message = new StringBuffer();
// message.append("Commercial support for Spring Boot " + javaProjectGen.getName() + " ends on: ");
// message.append(javaProjectGen.getCommercialSupportEndDate());
//
// return createDiagnostic(problemType, message.toString());
// }
// return null;
// }
// }
//
// private static class UnsupportedOssValidator extends AbstractDiagnosticValidator {
//
// private SpringProjectsProvider provider;
//
// public UnsupportedOssValidator(DiagnosticSeverityProvider diagnosticSeverityProvider, SpringProjectsProvider provider) {
// super(diagnosticSeverityProvider);
// this.provider = provider;
// }
//
// @Override
// public Diagnostic validate(IJavaProject javaProject, Version javaProjectVersion) throws Exception {
// ResolvedSpringProject springProject = provider.getProject(SpringProjectUtil.SPRING_BOOT);
// Generation javaProjectGen = getGenerationForJavaProject(javaProject, springProject);
// Assert.isLegal(javaProjectGen != null, "Unable to find Spring Project Generation for project: " + javaProjectVersion.toString());
//
// if (!VersionValidationUtils.isOssValid(javaProjectGen)) {
//
// VersionValidationProblemType problemType = VersionValidationProblemType.UNSUPPORTED_OSS_VERSION;
//
// StringBuffer message = new StringBuffer();
// message.append("OSS support for Spring Boot " + javaProjectGen.getName() + " no longer available, ended on: ");
// message.append(javaProjectGen.getOssSupportEndDate());
//
// return createDiagnostic(problemType, message.toString());
// }
// return null;
// }
// }
//
// private static class UnsupportedCommercialValidator extends AbstractDiagnosticValidator {
//
// private SpringProjectsProvider provider;
//
// public UnsupportedCommercialValidator(DiagnosticSeverityProvider diagnosticSeverityProvider, SpringProjectsProvider provider) {
// super(diagnosticSeverityProvider);
// this.provider = provider;
// }
//
// @Override
// public Diagnostic validate(IJavaProject javaProject, Version javaProjectVersion) throws Exception {
// ResolvedSpringProject springProject = provider.getProject(SpringProjectUtil.SPRING_BOOT);
// Generation javaProjectGen = getGenerationForJavaProject(javaProject, springProject);
// Assert.isLegal(javaProjectGen != null, "Unable to find Spring Project Generation for project: " + javaProjectVersion.toString());
//
// if (!VersionValidationUtils.isCommercialValid(javaProjectGen)) {
//
// VersionValidationProblemType problemType = VersionValidationProblemType.UNSUPPORTED_COMMERCIAL_VERSION;
//
// StringBuffer message = new StringBuffer();
// message.append("Commercial support for Spring Boot " + javaProjectGen.getName() + " no longer available, ended on: ");
// message.append(javaProjectGen.getCommercialSupportEndDate());
//
// return createDiagnostic(problemType, message.toString());
// }
// return null;
// }
// }
}

View File

@@ -1,21 +0,0 @@
/*******************************************************************************
* 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.preferences;
// TODO: integrate with actual LS preferences
public class VersionValidationPreferences {
private static final String DEFAULT_SPRING_PROJECT_URL = "https://spring.io/api/projects";
public String getSpringProjectsUrl() {
return DEFAULT_SPRING_PROJECT_URL;
}
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2022 VMware, Inc.
* Copyright (c) 2022, 2023 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
@@ -23,13 +23,13 @@ import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemTy
public enum VersionValidationProblemType implements ProblemType {
// SUPPORTED_OSS_VERSION(HINT, "Supported OSS Boot Version", "Supported OSS Boot Version"),
//
// UNSUPPORTED_OSS_VERSION(ERROR, "Unsupported OSS Version", "Unsupported OSS Version"),
//
// UNSUPPORTED_COMMERCIAL_VERSION(ERROR, "Unsupported Commercial Version", "Unsupported Commercial Version"),
//
// SUPPORTED_COMMERCIAL_VERSION(HINT, "Supported Commercial Version", "Supported Commercial Version"),
SUPPORTED_OSS_VERSION(HINT, "Supported OSS Boot Version", "Supported OSS Boot Version"),
UNSUPPORTED_OSS_VERSION(ERROR, "Unsupported OSS Version", "Unsupported OSS Version"),
UNSUPPORTED_COMMERCIAL_VERSION(ERROR, "Unsupported Commercial Version", "Unsupported Commercial Version"),
SUPPORTED_COMMERCIAL_VERSION(HINT, "Supported Commercial Version", "Supported Commercial Version"),
UPDATE_LATEST_MAJOR_VERSION(IGNORE, "Update to Latest Major Version", "Update to Latest Major Version"),

View File

@@ -309,6 +309,30 @@
},
"order": 7,
"problemTypes": [
{
"code": "SUPPORTED_OSS_VERSION",
"label": "Supported OSS Boot Version",
"description": "Supported OSS Boot Version",
"defaultSeverity": "HINT"
},
{
"code": "UNSUPPORTED_OSS_VERSION",
"label": "Unsupported OSS Version",
"description": "Unsupported OSS Version",
"defaultSeverity": "ERROR"
},
{
"code": "UNSUPPORTED_COMMERCIAL_VERSION",
"label": "Unsupported Commercial Version",
"description": "Unsupported Commercial Version",
"defaultSeverity": "ERROR"
},
{
"code": "SUPPORTED_COMMERCIAL_VERSION",
"label": "Supported Commercial Version",
"description": "Supported Commercial Version",
"defaultSeverity": "HINT"
},
{
"code": "UPDATE_LATEST_MAJOR_VERSION",
"label": "Update to Latest Major Version",

View File

@@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
@@ -26,7 +25,6 @@ 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.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.json.Generation;
import org.springframework.ide.vscode.boot.validation.generations.json.Link;
@@ -41,7 +39,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@BootLanguageServerTest
@Import(HoverTestConf.class)
@Disabled
public class ProjectGenerationsValidationTest {
@Autowired private BootLanguageServerHarness harness;
@@ -58,9 +55,7 @@ public class ProjectGenerationsValidationTest {
@Test
void testProjectsInfoFromSpringIo() throws Exception {
String url = "https://spring.io/api/projects";
SpringProjectsClient client = new SpringProjectsClient(url);
SpringProjectsProvider cache = new SpringIoProjectsProvider(client);
SpringProjectsProvider cache = new SpringIoProjectsProvider("https://api.spring.io/projects");
SpringProject project = cache.getProject("spring-boot");
assertNotNull(project);
@@ -68,7 +63,7 @@ public class ProjectGenerationsValidationTest {
assertEquals("spring-boot", project.getSlug());
Link generationsUrl = project.get_links().getGenerations();
assertNotNull(generationsUrl);
assertEquals("https://spring.io/api/projects/spring-boot/generations", generationsUrl.getHref());
assertEquals("https://api.spring.io/projects/spring-boot/generations", generationsUrl.getHref());
project = cache.getProject("spring-integration");
assertNotNull(project);
@@ -76,11 +71,14 @@ public class ProjectGenerationsValidationTest {
assertEquals("spring-integration", project.getSlug());
generationsUrl = project.get_links().getGenerations();
assertNotNull(generationsUrl);
assertEquals("https://spring.io/api/projects/spring-integration/generations", generationsUrl.getHref());
assertEquals("https://api.spring.io/projects/spring-integration/generations", generationsUrl.getHref());
// Enable when generations is actually available from spring.io
// Generations generations = cache.getGenerations("spring-boot");
// assertNotNull(generations);
ResolvedSpringProject resolvedProject = cache.getProject("spring-boot");
assertNotNull(resolvedProject);
List<Generation> generations = resolvedProject.getGenerations();
assertNotNull(generations);
assertTrue(generations.size() > 5);
}
@Test

View File

@@ -830,6 +830,54 @@
"ON"
]
},
"spring-boot.ls.problem.version-validation.SUPPORTED_OSS_VERSION": {
"type": "string",
"default": "HINT",
"description": "Supported OSS Boot Version",
"enum": [
"IGNORE",
"INFO",
"WARNING",
"HINT",
"ERROR"
]
},
"spring-boot.ls.problem.version-validation.UNSUPPORTED_OSS_VERSION": {
"type": "string",
"default": "ERROR",
"description": "Unsupported OSS Version",
"enum": [
"IGNORE",
"INFO",
"WARNING",
"HINT",
"ERROR"
]
},
"spring-boot.ls.problem.version-validation.UNSUPPORTED_COMMERCIAL_VERSION": {
"type": "string",
"default": "ERROR",
"description": "Unsupported Commercial Version",
"enum": [
"IGNORE",
"INFO",
"WARNING",
"HINT",
"ERROR"
]
},
"spring-boot.ls.problem.version-validation.SUPPORTED_COMMERCIAL_VERSION": {
"type": "string",
"default": "HINT",
"description": "Supported Commercial Version",
"enum": [
"IGNORE",
"INFO",
"WARNING",
"HINT",
"ERROR"
]
},
"spring-boot.ls.problem.version-validation.UPDATE_LATEST_MAJOR_VERSION": {
"type": "string",
"default": "IGNORE",
@@ -910,4 +958,4 @@
"extensionDependencies": [
"redhat.java"
]
}
}