From 791659dd5e60709f28f9afa7983cee5375acb136 Mon Sep 17 00:00:00 2001 From: OrlovAlexander <35396155+OrlovAlexander85@users.noreply.github.com> Date: Tue, 9 Apr 2024 15:22:11 +0200 Subject: [PATCH] SONAR-22018 introduce version EOL to properties, and update GlobalAction --- gradle.properties | 7 +++++ .../org/sonar/server/ui/ws/GlobalAction.java | 11 +++++++- .../sonar/server/ui/ws/global-example.json | 1 + .../sonar/server/ui/ws/GlobalActionTest.java | 23 ++++++++++++++-- sonar-plugin-api-impl/build.gradle | 3 ++- .../sonar/api/internal/MetadataLoader.java | 26 +++++++++++++------ .../src/main/resources/sq-version-eol.txt | 1 + .../api/internal/MetadataLoaderTest.java | 13 ++++++++++ 8 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 sonar-plugin-api-impl/src/main/resources/sq-version-eol.txt diff --git a/gradle.properties b/gradle.properties index 2a0e987ed24..566cba8aa11 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,12 @@ group=org.sonarsource.sonarqube version=9.9.5 + +# End Of Life date for the version. MMF-3763. format is yyyy-MM-dd +# 6 months from the release date for non LTA versions +# 30 months from the release date for LTA versions +# No change required for patch versions +versionEOL=2025-08-07 + description=Open source platform for continuous inspection of code quality projectTitle=SonarQube org.gradle.jvmargs=-Xmx2048m diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/GlobalAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/GlobalAction.java index 1f4f1007ee3..fb4959fff8b 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/GlobalAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/GlobalAction.java @@ -28,9 +28,11 @@ import org.sonar.api.config.Configuration; import org.sonar.api.platform.Server; import org.sonar.api.resources.ResourceType; import org.sonar.api.resources.ResourceTypes; +import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService.NewController; +import org.sonar.api.utils.System2; import org.sonar.api.utils.text.JsonWriter; import org.sonar.api.web.page.Page; import org.sonar.core.platform.PlatformEditionProvider; @@ -47,6 +49,7 @@ import org.sonar.server.user.UserSession; import static org.sonar.api.CoreProperties.DEVELOPER_AGGREGATED_INFO_DISABLED; import static org.sonar.api.CoreProperties.RATING_GRID; +import static org.sonar.api.internal.MetadataLoader.loadSqVersionEol; import static org.sonar.core.config.WebConstants.SONAR_LF_ENABLE_GRAVATAR; import static org.sonar.core.config.WebConstants.SONAR_LF_GRAVATAR_SERVER_URL; import static org.sonar.core.config.WebConstants.SONAR_LF_LOGO_URL; @@ -112,7 +115,8 @@ public class GlobalAction implements NavigationWsAction, Startable { .setHandler(this) .setInternal(true) .setResponseExample(getClass().getResource("global-example.json")) - .setSince("5.2"); + .setSince("5.2") + .setChangelog(new Change("9.9.5", "Field 'versionEOL' added, to indicate the end of support of installed version.")); } @Override @@ -125,6 +129,7 @@ public class GlobalAction implements NavigationWsAction, Startable { writeDeprecatedLogoProperties(json); writeQualifiers(json); writeVersion(json); + writeVersionEol(json); writeDatabaseProduction(json); writeInstanceUsesDefaultAdminCredentials(json); editionProvider.get().ifPresent(e -> json.prop("edition", e.name().toLowerCase(Locale.ENGLISH))); @@ -175,6 +180,10 @@ public class GlobalAction implements NavigationWsAction, Startable { json.prop("version", displayVersion); } + private void writeVersionEol(JsonWriter json) { + json.prop("versionEOL", loadSqVersionEol(System2.INSTANCE)); + } + private void writeDatabaseProduction(JsonWriter json) { json.prop("productionDatabase", !dbClient.getDatabase().getDialect().getId().equals(H2.ID)); } diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/ui/ws/global-example.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/ui/ws/global-example.json index a1619ee69fd..ec6d8c052c5 100644 --- a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/ui/ws/global-example.json +++ b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/ui/ws/global-example.json @@ -24,6 +24,7 @@ "POL" ], "version": "6.2", + "versionEOL": "2025-01-01", "productionDatabase": true, "canAdmin": false, "standalone": true, diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java index 19a79bf4ec5..c0f77e2a7ea 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java @@ -19,10 +19,13 @@ */ package org.sonar.server.ui.ws; +import java.util.Objects; import java.util.Optional; import org.junit.Rule; import org.junit.Test; import org.sonar.api.config.internal.MapSettings; +import org.mockito.MockedStatic; +import org.sonar.api.internal.MetadataLoader; import org.sonar.api.platform.Server; import org.sonar.api.resources.ResourceType; import org.sonar.api.resources.ResourceTypeTree; @@ -50,6 +53,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.when; import static org.sonar.test.JsonAssert.assertJson; @@ -184,6 +188,15 @@ public class GlobalActionTest { "}"); } + @Test + public void execute_shouldReturnVersionEol() { + init(); + try (MockedStatic mocked = mockStatic(MetadataLoader.class)) { + mocked.when(() -> MetadataLoader.loadSqVersionEol(any())).thenReturn("2025-01-01"); + assertThat(call()).contains("\"versionEOL\":\"2025-01-01\""); + } + } + @Test public void functional_version_when_4_digits() { init(); @@ -283,8 +296,14 @@ public class GlobalActionTest { when(nodeInformation.isStandalone()).thenReturn(true); when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.COMMUNITY)); - String result = call(); - assertJson(result).isSimilarTo(ws.getDef().responseExampleAsString()); + + try (MockedStatic mocked = mockStatic(MetadataLoader.class)) { + mocked.when(() -> MetadataLoader.loadSqVersionEol(any())).thenReturn("2025-01-01"); + + String result = call(); + + assertJson(result).isSimilarTo(Objects.requireNonNull(ws.getDef().responseExampleAsString())); + } } @Test diff --git a/sonar-plugin-api-impl/build.gradle b/sonar-plugin-api-impl/build.gradle index 51480338d9d..a55d546a8f6 100644 --- a/sonar-plugin-api-impl/build.gradle +++ b/sonar-plugin-api-impl/build.gradle @@ -28,7 +28,8 @@ dependencies { import org.apache.tools.ant.filters.ReplaceTokens processResources { filter ReplaceTokens, tokens: [ - 'project.version': project.version + 'project.version': project.version, + 'versionEOL': project.properties["versionEOL"] ] } diff --git a/sonar-plugin-api-impl/src/main/java/org/sonar/api/internal/MetadataLoader.java b/sonar-plugin-api-impl/src/main/java/org/sonar/api/internal/MetadataLoader.java index e0c75d17013..16ff62524fa 100644 --- a/sonar-plugin-api-impl/src/main/java/org/sonar/api/internal/MetadataLoader.java +++ b/sonar-plugin-api-impl/src/main/java/org/sonar/api/internal/MetadataLoader.java @@ -28,6 +28,7 @@ import org.sonar.api.SonarEdition; import org.sonar.api.utils.System2; import org.sonar.api.utils.Version; +import static java.lang.String.format; import static org.apache.commons.lang.StringUtils.trimToEmpty; /** @@ -40,6 +41,8 @@ public class MetadataLoader { private static final String SQ_VERSION_FILE_PATH = "/sq-version.txt"; private static final String SONAR_API_VERSION_FILE_PATH = "/sonar-api-version.txt"; private static final String EDITION_FILE_PATH = "/sonar-edition.txt"; + private static final String SQ_VERSION_EOL_FILE_PATH = "/sq-version-eol.txt"; + public static final String CAN_NOT_LOAD_FROM_CLASSPATH = "Can not load %s from classpath"; private MetadataLoader() { // only static methods @@ -48,18 +51,25 @@ public class MetadataLoader { public static Version loadApiVersion(System2 system) { return getVersion(system, SONAR_API_VERSION_FILE_PATH); } + public static Version loadSQVersion(System2 system) { return getVersion(system, SQ_VERSION_FILE_PATH); } + public static String loadSqVersionEol(System2 system) { + return getParamFromFile(system, SQ_VERSION_EOL_FILE_PATH); + } + private static Version getVersion(System2 system, String versionFilePath) { - URL url = system.getResource(versionFilePath); + return Version.parse(getParamFromFile(system, versionFilePath)); + } - try (Scanner scanner = new Scanner(url.openStream(), StandardCharsets.UTF_8.name())) { - String versionInFile = scanner.nextLine(); - return Version.parse(versionInFile); + private static String getParamFromFile(System2 system, String filePath) { + URL url = system.getResource(filePath); + try (Scanner scanner = new Scanner(url.openStream(), StandardCharsets.UTF_8)) { + return scanner.nextLine(); } catch (IOException e) { - throw new IllegalStateException("Can not load " + versionFilePath + " from classpath ", e); + throw new IllegalStateException(format(CAN_NOT_LOAD_FROM_CLASSPATH, filePath), e); } } @@ -68,11 +78,11 @@ public class MetadataLoader { if (url == null) { return SonarEdition.COMMUNITY; } - try (Scanner scanner = new Scanner(url.openStream(), StandardCharsets.UTF_8.name())) { + try (Scanner scanner = new Scanner(url.openStream(), StandardCharsets.UTF_8)) { String editionInFile = scanner.nextLine(); return parseEdition(editionInFile); } catch (IOException e) { - throw new IllegalStateException("Can not load " + EDITION_FILE_PATH + " from classpath", e); + throw new IllegalStateException(format(CAN_NOT_LOAD_FROM_CLASSPATH, EDITION_FILE_PATH), e); } } @@ -81,7 +91,7 @@ public class MetadataLoader { try { return SonarEdition.valueOf(str); } catch (IllegalArgumentException e) { - throw new IllegalStateException(String.format("Invalid edition found in '%s': '%s'", EDITION_FILE_PATH, str)); + throw new IllegalStateException(format("Invalid edition found in '%s': '%s'", EDITION_FILE_PATH, str)); } } } diff --git a/sonar-plugin-api-impl/src/main/resources/sq-version-eol.txt b/sonar-plugin-api-impl/src/main/resources/sq-version-eol.txt new file mode 100644 index 00000000000..154f9322c6d --- /dev/null +++ b/sonar-plugin-api-impl/src/main/resources/sq-version-eol.txt @@ -0,0 +1 @@ +@versionEOL@ diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/internal/MetadataLoaderTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/internal/MetadataLoaderTest.java index 3ee4ec5df9a..31628e5ebda 100644 --- a/sonar-plugin-api-impl/src/test/java/org/sonar/api/internal/MetadataLoaderTest.java +++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/internal/MetadataLoaderTest.java @@ -78,4 +78,17 @@ public class MetadataLoaderTest { .hasMessageContaining("Can not load /sonar-api-version.txt from classpath"); } + @Test + public void loadSqVersionEol_shouldLoadCorrectEol() { + String eol = MetadataLoader.loadSqVersionEol(System2.INSTANCE); + assertThat(eol).isNotNull(); + } + + @Test + public void loadSqVersionEol_whenFileNotFound_shouldThrowException() throws MalformedURLException { + when(system.getResource(anyString())).thenReturn(new File("target/unknown").toURI().toURL()); + assertThatThrownBy(() -> MetadataLoader.loadSqVersionEol(system)) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Can not load /sq-version-eol.txt from classpath"); + } } -- 2.39.5